From 804b7cb33295315b9a373a2ec7e25f8cb659b343 Mon Sep 17 00:00:00 2001 From: David Zhao Date: Fri, 25 Dec 2020 22:31:11 -0800 Subject: [PATCH] JWT token based auth --- cmd/cli/commands/room.go | 4 +- cmd/server/main.go | 61 ++++++++-- cmd/server/wire.go | 3 +- cmd/server/wire_gen.go | 5 +- go.mod | 2 + go.sum | 8 ++ pkg/auth/authfakes/fake_key_provider.go | 111 +++++++++++++++++ pkg/auth/authfakes/fake_token_issuer.go | 119 ++++++++++++++++++ pkg/auth/authfakes/fake_token_verifier.go | 107 +++++++++++++++++ pkg/auth/grants.go | 7 ++ pkg/auth/interfaces.go | 27 +++++ pkg/auth/issuer.go | 41 +++++++ pkg/auth/issuer_test.go | 47 ++++++++ pkg/auth/provider.go | 44 +++++++ pkg/auth/provider_test.go | 40 +++++++ pkg/auth/verifier.go | 54 +++++++++ pkg/auth/verifier_test.go | 52 ++++++++ pkg/rtc/errors.go | 4 +- pkg/rtc/manager.go | 57 ++++++--- pkg/rtc/manager_test.go | 1 + pkg/rtc/room.go | 14 +-- pkg/rtc/room_test.go | 31 ++++- pkg/service/auth.go | 126 +++++++++++++++++++ pkg/service/auth_test.go | 59 +++++++++ pkg/service/rtc.go | 19 ++- pkg/service/simpleroom.go | 19 ++- pkg/utils/id.go | 1 + pkg/utils/secret.go | 12 ++ proto/livekit/model.pb.go | 140 +++++++++++----------- proto/livekit/room.pb.go | 85 +++++++------ proto/livekit/room.twirp.go | 38 +++--- proto/model.proto | 16 +-- proto/room.proto | 9 +- 33 files changed, 1169 insertions(+), 194 deletions(-) create mode 100644 pkg/auth/authfakes/fake_key_provider.go create mode 100644 pkg/auth/authfakes/fake_token_issuer.go create mode 100644 pkg/auth/authfakes/fake_token_verifier.go create mode 100644 pkg/auth/grants.go create mode 100644 pkg/auth/interfaces.go create mode 100644 pkg/auth/issuer.go create mode 100644 pkg/auth/issuer_test.go create mode 100644 pkg/auth/provider.go create mode 100644 pkg/auth/provider_test.go create mode 100644 pkg/auth/verifier.go create mode 100644 pkg/auth/verifier_test.go create mode 100644 pkg/rtc/manager_test.go create mode 100644 pkg/service/auth.go create mode 100644 pkg/service/auth_test.go create mode 100644 pkg/utils/secret.go diff --git a/cmd/cli/commands/room.go b/cmd/cli/commands/room.go index 3eb7934be..92bfacf0e 100644 --- a/cmd/cli/commands/room.go +++ b/cmd/cli/commands/room.go @@ -62,7 +62,7 @@ func createRoom(c *cli.Context) error { func getRoom(c *cli.Context) error { roomId := c.String("room-id") room, err := roomClient.GetRoom(context.Background(), &livekit.GetRoomRequest{ - RoomId: roomId, + Room: roomId, }) if err != nil { return err @@ -75,7 +75,7 @@ func getRoom(c *cli.Context) error { func deleteRoom(c *cli.Context) error { roomId := c.String("room-id") _, err := roomClient.DeleteRoom(context.Background(), &livekit.DeleteRoomRequest{ - RoomId: roomId, + Room: roomId, }) if err != nil { return err diff --git a/cmd/server/main.go b/cmd/server/main.go index 80db962cc..2baf51cdb 100644 --- a/cmd/server/main.go +++ b/cmd/server/main.go @@ -1,6 +1,7 @@ package main import ( + "bytes" "context" "errors" "fmt" @@ -15,6 +16,7 @@ import ( "github.com/urfave/cli/v2" "github.com/urfave/negroni" + "github.com/livekit/livekit-server/pkg/auth" "github.com/livekit/livekit-server/pkg/config" "github.com/livekit/livekit-server/pkg/logger" "github.com/livekit/livekit-server/pkg/node" @@ -29,10 +31,22 @@ func main() { Flags: []cli.Flag{ &cli.StringFlag{ Name: "config", + Usage: "path to LiveKit config", EnvVars: []string{"LIVEKIT_CONFIG"}, }, + &cli.StringFlag{ + Name: "key-file", + Usage: "path to file that contains API keys/secrets", + EnvVars: []string{"KEY_FILE"}, + }, + &cli.StringFlag{ + Name: "keys", + Usage: "API keys/secret pairs (key:secret, one per line)", + EnvVars: []string{"KEY_FILE"}, + }, &cli.BoolFlag{ - Name: "dev", + Name: "dev", + Usage: "when set, token validation will be disabled", }, }, Action: startServer, @@ -50,14 +64,20 @@ func startServer(c *cli.Context) error { } conf.UpdateFromCLI(c) + var keyProvider auth.KeyProvider if conf.Development { logger.InitDevelopment() } else { logger.InitProduction() + // require a key provider + if keyProvider, err = createKeyProvider(c.String("key-file"), c.String("keys")); err != nil { + return err + } + service.AuthRequired = true } - server, err := InitializeServer(conf) + server, err := InitializeServer(conf, keyProvider) if err != nil { return err } @@ -74,6 +94,25 @@ func startServer(c *cli.Context) error { return server.Start() } +func createKeyProvider(keyFile, keys string) (auth.KeyProvider, error) { + // prefer keyfile if set + if keyFile != "" { + f, err := os.Open(keyFile) + if err != nil { + return nil, err + } + defer f.Close() + return auth.NewFileBasedKeyProvider(f) + } + + if keys != "" { + r := bytes.NewReader([]byte(keys)) + return auth.NewFileBasedKeyProvider(r) + } + + return nil, errors.New("one of key-file or keys must be provided in order to support a secure installation") +} + type LivekitServer struct { config *config.Config roomServer livekit.TwirpServer @@ -86,24 +125,29 @@ type LivekitServer struct { func NewLivekitServer(conf *config.Config, roomService livekit.RoomService, - rtcService *service.RTCService) (s *LivekitServer, err error) { + rtcService *service.RTCService, + keyProvider auth.KeyProvider) (s *LivekitServer, err error) { s = &LivekitServer{ config: conf, roomServer: livekit.NewRoomServiceServer(roomService), rtcService: rtcService, } - roomHandler := configureMiddlewares(conf, s.roomServer) + middlewares := make([]negroni.Handler, 0) + if keyProvider != nil { + middlewares = append(middlewares, service.NewAPIKeyAuthMiddleware(keyProvider)) + } + s.roomHttp = &http.Server{ Addr: fmt.Sprintf(":%d", conf.APIPort), - Handler: roomHandler, + Handler: configureMiddlewares(conf, s.roomServer, middlewares...), } rtcHandler := http.NewServeMux() rtcHandler.Handle("/rtc", rtcService) s.rtcHttp = &http.Server{ Addr: fmt.Sprintf(":%d", conf.RTCPort), - Handler: configureMiddlewares(conf, rtcHandler), + Handler: configureMiddlewares(conf, rtcHandler, middlewares...), } return @@ -162,9 +206,12 @@ func (s *LivekitServer) Stop() { s.doneChan <- true } -func configureMiddlewares(conf *config.Config, handler http.Handler) *negroni.Negroni { +func configureMiddlewares(conf *config.Config, handler http.Handler, middlewares ...negroni.Handler) *negroni.Negroni { n := negroni.New() n.Use(negroni.NewRecovery()) + for _, m := range middlewares { + n.Use(m) + } n.UseHandler(handler) return n } diff --git a/cmd/server/wire.go b/cmd/server/wire.go index f4d2b4ef1..eac024958 100644 --- a/cmd/server/wire.go +++ b/cmd/server/wire.go @@ -5,12 +5,13 @@ package main import ( "github.com/google/wire" + "github.com/livekit/livekit-server/pkg/auth" "github.com/livekit/livekit-server/pkg/config" "github.com/livekit/livekit-server/pkg/node" "github.com/livekit/livekit-server/pkg/service" ) -func InitializeServer(conf *config.Config) (*LivekitServer, error) { +func InitializeServer(conf *config.Config, keyProvider auth.KeyProvider) (*LivekitServer, error) { wire.Build( NewLivekitServer, node.NodeSet, diff --git a/cmd/server/wire_gen.go b/cmd/server/wire_gen.go index 78f2c3791..d195fd11c 100644 --- a/cmd/server/wire_gen.go +++ b/cmd/server/wire_gen.go @@ -6,6 +6,7 @@ package main import ( + "github.com/livekit/livekit-server/pkg/auth" "github.com/livekit/livekit-server/pkg/config" "github.com/livekit/livekit-server/pkg/node" "github.com/livekit/livekit-server/pkg/service" @@ -13,7 +14,7 @@ import ( // Injectors from wire.go: -func InitializeServer(conf *config.Config) (*LivekitServer, error) { +func InitializeServer(conf *config.Config, keyProvider auth.KeyProvider) (*LivekitServer, error) { nodeNode, err := node.NewLocalNode(conf) if err != nil { return nil, err @@ -27,7 +28,7 @@ func InitializeServer(conf *config.Config) (*LivekitServer, error) { return nil, err } rtcService := service.NewRTCService(conf, roomManager) - livekitServer, err := NewLivekitServer(conf, roomService, rtcService) + livekitServer, err := NewLivekitServer(conf, roomService, rtcService, keyProvider) if err != nil { return nil, err } diff --git a/go.mod b/go.mod index a386e9718..494df38eb 100644 --- a/go.mod +++ b/go.mod @@ -9,6 +9,7 @@ require ( github.com/gorilla/websocket v1.4.2 github.com/lithammer/shortuuid/v3 v3.0.4 github.com/lunixbochs/vtclean v1.0.0 // indirect + github.com/lytics/base62 v0.0.0-20180808010106-0ee4de5a5d6d github.com/magefile/mage v1.10.0 github.com/manifoldco/promptui v0.8.0 github.com/maxbrunsfeld/counterfeiter/v6 v6.3.0 @@ -30,5 +31,6 @@ require ( golang.org/x/mod v0.4.0 // indirect golang.org/x/tools v0.0.0-20201222163215-f2e330f49058 // indirect google.golang.org/protobuf v1.25.0 + gopkg.in/square/go-jose.v2 v2.5.1 gopkg.in/yaml.v3 v3.0.0-20200615113413-eeeca48fe776 ) diff --git a/go.sum b/go.sum index f099301d3..f673aed67 100644 --- a/go.sum +++ b/go.sum @@ -21,9 +21,11 @@ github.com/Shopify/toxiproxy v2.1.4+incompatible/go.mod h1:OXgGpZ6Cli1/URJOF1DMx github.com/VividCortex/gohistogram v1.0.0/go.mod h1:Pf5mBqqDxYaXu3hDrrU+w6nw50o/4+TcAqDqk/vUH7g= github.com/afex/hystrix-go v0.0.0-20180502004556-fa1af6a1f4f5/go.mod h1:SkGFH1ia65gfNATL8TAiHDNxPzPdmEL5uirI2Uyuz6c= github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= +github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751 h1:JYp7IbQjafoB+tBA3gMyHYHrpOtNuDiK/uB5uXxq5wM= github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= github.com/alecthomas/units v0.0.0-20190717042225-c3de453c63f4/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= +github.com/alecthomas/units v0.0.0-20190924025748-f65c72e2690d h1:UQZhZ2O0vMHr2cI+DC1Mbh0TJxzA3RcLoMsFw+aXw7E= github.com/alecthomas/units v0.0.0-20190924025748-f65c72e2690d/go.mod h1:rBZYJk541a8SKzHPHnH3zbiI+7dagKZ0cgpgrD7Fyho= github.com/apache/thrift v0.12.0/go.mod h1:cp2SuWMxlEZw2r+iP2GNCdIi4C1qmUzdZFSVb+bacwQ= github.com/apache/thrift v0.13.0/go.mod h1:cp2SuWMxlEZw2r+iP2GNCdIi4C1qmUzdZFSVb+bacwQ= @@ -71,6 +73,7 @@ github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSs github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/desertbit/timer v0.0.0-20180107155436-c41aec40b27f/go.mod h1:xH/i4TFMt8koVQZ6WFms69WAsDWr2XsYL3Hkl7jkoLE= +github.com/dgrijalva/jwt-go v3.2.0+incompatible h1:7qlOGliEKZXTDg6OTjfoBKDXWrumCAMpl/TFQ4/5kLM= github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ= github.com/dgryski/go-sip13 v0.0.0-20181026042036-e10d5fee7954/go.mod h1:vAd38F8PWV+bWy6jNmig1y/TA+kYO4g3RSRF0IAv0no= github.com/dustin/go-humanize v0.0.0-20171111073723-bb3d318650d4/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk= @@ -224,6 +227,8 @@ github.com/lunixbochs/vtclean v0.0.0-20180621232353-2d01aacdc34a/go.mod h1:pHhQN github.com/lunixbochs/vtclean v1.0.0 h1:xu2sLAri4lGiovBDQKxl5mrXyESr3gUr5m5SM5+LVb8= github.com/lunixbochs/vtclean v1.0.0/go.mod h1:pHhQNgMf3btfWnGBVipUOjRYhoOsdGqdm/+2c2E2WMI= github.com/lyft/protoc-gen-validate v0.0.13/go.mod h1:XbGvPuh87YZc5TdIa2/I4pLk0QoUACkjt2znoq26NVQ= +github.com/lytics/base62 v0.0.0-20180808010106-0ee4de5a5d6d h1:HONlVR8gkr5QibYNVFtj8ajfqRAKt21DmdzeZXZl6VQ= +github.com/lytics/base62 v0.0.0-20180808010106-0ee4de5a5d6d/go.mod h1:nFZ1y9JiUDciefRL0X6OTobqQGgFCR+lbnn1lWsoQk0= github.com/magefile/mage v1.10.0 h1:3HiXzCUY12kh9bIuyXShaVe529fJfyqoVM42o/uom2g= github.com/magefile/mage v1.10.0/go.mod h1:z5UZb/iS3GoOSn0JgWuiw7dxlurVYTu+/jHXqQg881A= github.com/magiconair/properties v1.8.1 h1:ZC2Vc7/ZFkGmsVC9KvOjumD+G5lXy2RtTKyzRKO2BQ4= @@ -672,6 +677,7 @@ google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpAD google.golang.org/protobuf v1.24.0/go.mod h1:r/3tXBNzIEhYS9I1OUVjXDlt8tc493IdKGjtUeSXeh4= google.golang.org/protobuf v1.25.0 h1:Ejskq+SyPohKW+1uil0JJMtmHCgJPJ/qWTxr8qp+R4c= google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c= +gopkg.in/alecthomas/kingpin.v2 v2.2.6 h1:jMFz6MfLP0/4fUyZle81rXUoxOBFi19VUFKVDOQfozc= gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= @@ -686,6 +692,8 @@ gopkg.in/gcfg.v1 v1.2.3/go.mod h1:yesOnuUOFQAhST5vPY4nbZsb/huCgGGXlipJsBn0b3o= gopkg.in/ini.v1 v1.51.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= gopkg.in/ini.v1 v1.51.1/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= gopkg.in/resty.v1 v1.12.0/go.mod h1:mDo4pnntr5jdWRML875a/NmxYqAlA73dVijT2AXvQQo= +gopkg.in/square/go-jose.v2 v2.5.1 h1:7odma5RETjNHWJnR32wx8t+Io4djHE1PqxCFx3iiZ2w= +gopkg.in/square/go-jose.v2 v2.5.1/go.mod h1:M9dMgbHiYLoDGQrXy7OpJDJWiKiU//h+vD76mk0e1AI= gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ= gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw= gopkg.in/warnings.v0 v0.1.2/go.mod h1:jksf8JmL6Qr/oQM2OXTHunEvvTAsrWBLb6OOjuVWRNI= diff --git a/pkg/auth/authfakes/fake_key_provider.go b/pkg/auth/authfakes/fake_key_provider.go new file mode 100644 index 000000000..530c30508 --- /dev/null +++ b/pkg/auth/authfakes/fake_key_provider.go @@ -0,0 +1,111 @@ +// Code generated by counterfeiter. DO NOT EDIT. +package authfakes + +import ( + "sync" + + "github.com/livekit/livekit-server/pkg/auth" +) + +type FakeKeyProvider struct { + GetSecretStub func(string) string + getSecretMutex sync.RWMutex + getSecretArgsForCall []struct { + arg1 string + } + getSecretReturns struct { + result1 string + } + getSecretReturnsOnCall map[int]struct { + result1 string + } + invocations map[string][][]interface{} + invocationsMutex sync.RWMutex +} + +func (fake *FakeKeyProvider) GetSecret(arg1 string) string { + fake.getSecretMutex.Lock() + ret, specificReturn := fake.getSecretReturnsOnCall[len(fake.getSecretArgsForCall)] + fake.getSecretArgsForCall = append(fake.getSecretArgsForCall, struct { + arg1 string + }{arg1}) + stub := fake.GetSecretStub + fakeReturns := fake.getSecretReturns + fake.recordInvocation("GetSecret", []interface{}{arg1}) + fake.getSecretMutex.Unlock() + if stub != nil { + return stub(arg1) + } + if specificReturn { + return ret.result1 + } + return fakeReturns.result1 +} + +func (fake *FakeKeyProvider) GetSecretCallCount() int { + fake.getSecretMutex.RLock() + defer fake.getSecretMutex.RUnlock() + return len(fake.getSecretArgsForCall) +} + +func (fake *FakeKeyProvider) GetSecretCalls(stub func(string) string) { + fake.getSecretMutex.Lock() + defer fake.getSecretMutex.Unlock() + fake.GetSecretStub = stub +} + +func (fake *FakeKeyProvider) GetSecretArgsForCall(i int) string { + fake.getSecretMutex.RLock() + defer fake.getSecretMutex.RUnlock() + argsForCall := fake.getSecretArgsForCall[i] + return argsForCall.arg1 +} + +func (fake *FakeKeyProvider) GetSecretReturns(result1 string) { + fake.getSecretMutex.Lock() + defer fake.getSecretMutex.Unlock() + fake.GetSecretStub = nil + fake.getSecretReturns = struct { + result1 string + }{result1} +} + +func (fake *FakeKeyProvider) GetSecretReturnsOnCall(i int, result1 string) { + fake.getSecretMutex.Lock() + defer fake.getSecretMutex.Unlock() + fake.GetSecretStub = nil + if fake.getSecretReturnsOnCall == nil { + fake.getSecretReturnsOnCall = make(map[int]struct { + result1 string + }) + } + fake.getSecretReturnsOnCall[i] = struct { + result1 string + }{result1} +} + +func (fake *FakeKeyProvider) Invocations() map[string][][]interface{} { + fake.invocationsMutex.RLock() + defer fake.invocationsMutex.RUnlock() + fake.getSecretMutex.RLock() + defer fake.getSecretMutex.RUnlock() + copiedInvocations := map[string][][]interface{}{} + for key, value := range fake.invocations { + copiedInvocations[key] = value + } + return copiedInvocations +} + +func (fake *FakeKeyProvider) recordInvocation(key string, args []interface{}) { + fake.invocationsMutex.Lock() + defer fake.invocationsMutex.Unlock() + if fake.invocations == nil { + fake.invocations = map[string][][]interface{}{} + } + if fake.invocations[key] == nil { + fake.invocations[key] = [][]interface{}{} + } + fake.invocations[key] = append(fake.invocations[key], args) +} + +var _ auth.KeyProvider = new(FakeKeyProvider) diff --git a/pkg/auth/authfakes/fake_token_issuer.go b/pkg/auth/authfakes/fake_token_issuer.go new file mode 100644 index 000000000..ecc00149c --- /dev/null +++ b/pkg/auth/authfakes/fake_token_issuer.go @@ -0,0 +1,119 @@ +// Code generated by counterfeiter. DO NOT EDIT. +package authfakes + +import ( + "sync" + "time" + + "github.com/livekit/livekit-server/pkg/auth" +) + +type FakeTokenIssuer struct { + CreateTokenStub func(*auth.GrantClaims, time.Duration) (string, error) + createTokenMutex sync.RWMutex + createTokenArgsForCall []struct { + arg1 *auth.GrantClaims + arg2 time.Duration + } + createTokenReturns struct { + result1 string + result2 error + } + createTokenReturnsOnCall map[int]struct { + result1 string + result2 error + } + invocations map[string][][]interface{} + invocationsMutex sync.RWMutex +} + +func (fake *FakeTokenIssuer) CreateToken(arg1 *auth.GrantClaims, arg2 time.Duration) (string, error) { + fake.createTokenMutex.Lock() + ret, specificReturn := fake.createTokenReturnsOnCall[len(fake.createTokenArgsForCall)] + fake.createTokenArgsForCall = append(fake.createTokenArgsForCall, struct { + arg1 *auth.GrantClaims + arg2 time.Duration + }{arg1, arg2}) + stub := fake.CreateTokenStub + fakeReturns := fake.createTokenReturns + fake.recordInvocation("CreateToken", []interface{}{arg1, arg2}) + fake.createTokenMutex.Unlock() + if stub != nil { + return stub(arg1, arg2) + } + if specificReturn { + return ret.result1, ret.result2 + } + return fakeReturns.result1, fakeReturns.result2 +} + +func (fake *FakeTokenIssuer) CreateTokenCallCount() int { + fake.createTokenMutex.RLock() + defer fake.createTokenMutex.RUnlock() + return len(fake.createTokenArgsForCall) +} + +func (fake *FakeTokenIssuer) CreateTokenCalls(stub func(*auth.GrantClaims, time.Duration) (string, error)) { + fake.createTokenMutex.Lock() + defer fake.createTokenMutex.Unlock() + fake.CreateTokenStub = stub +} + +func (fake *FakeTokenIssuer) CreateTokenArgsForCall(i int) (*auth.GrantClaims, time.Duration) { + fake.createTokenMutex.RLock() + defer fake.createTokenMutex.RUnlock() + argsForCall := fake.createTokenArgsForCall[i] + return argsForCall.arg1, argsForCall.arg2 +} + +func (fake *FakeTokenIssuer) CreateTokenReturns(result1 string, result2 error) { + fake.createTokenMutex.Lock() + defer fake.createTokenMutex.Unlock() + fake.CreateTokenStub = nil + fake.createTokenReturns = struct { + result1 string + result2 error + }{result1, result2} +} + +func (fake *FakeTokenIssuer) CreateTokenReturnsOnCall(i int, result1 string, result2 error) { + fake.createTokenMutex.Lock() + defer fake.createTokenMutex.Unlock() + fake.CreateTokenStub = nil + if fake.createTokenReturnsOnCall == nil { + fake.createTokenReturnsOnCall = make(map[int]struct { + result1 string + result2 error + }) + } + fake.createTokenReturnsOnCall[i] = struct { + result1 string + result2 error + }{result1, result2} +} + +func (fake *FakeTokenIssuer) Invocations() map[string][][]interface{} { + fake.invocationsMutex.RLock() + defer fake.invocationsMutex.RUnlock() + fake.createTokenMutex.RLock() + defer fake.createTokenMutex.RUnlock() + copiedInvocations := map[string][][]interface{}{} + for key, value := range fake.invocations { + copiedInvocations[key] = value + } + return copiedInvocations +} + +func (fake *FakeTokenIssuer) recordInvocation(key string, args []interface{}) { + fake.invocationsMutex.Lock() + defer fake.invocationsMutex.Unlock() + if fake.invocations == nil { + fake.invocations = map[string][][]interface{}{} + } + if fake.invocations[key] == nil { + fake.invocations[key] = [][]interface{}{} + } + fake.invocations[key] = append(fake.invocations[key], args) +} + +var _ auth.TokenIssuer = new(FakeTokenIssuer) diff --git a/pkg/auth/authfakes/fake_token_verifier.go b/pkg/auth/authfakes/fake_token_verifier.go new file mode 100644 index 000000000..656354191 --- /dev/null +++ b/pkg/auth/authfakes/fake_token_verifier.go @@ -0,0 +1,107 @@ +// Code generated by counterfeiter. DO NOT EDIT. +package authfakes + +import ( + "sync" + + "github.com/livekit/livekit-server/pkg/auth" +) + +type FakeTokenVerifier struct { + VerifyStub func() (*auth.GrantClaims, error) + verifyMutex sync.RWMutex + verifyArgsForCall []struct { + } + verifyReturns struct { + result1 *auth.GrantClaims + result2 error + } + verifyReturnsOnCall map[int]struct { + result1 *auth.GrantClaims + result2 error + } + invocations map[string][][]interface{} + invocationsMutex sync.RWMutex +} + +func (fake *FakeTokenVerifier) Verify() (*auth.GrantClaims, error) { + fake.verifyMutex.Lock() + ret, specificReturn := fake.verifyReturnsOnCall[len(fake.verifyArgsForCall)] + fake.verifyArgsForCall = append(fake.verifyArgsForCall, struct { + }{}) + stub := fake.VerifyStub + fakeReturns := fake.verifyReturns + fake.recordInvocation("Verify", []interface{}{}) + fake.verifyMutex.Unlock() + if stub != nil { + return stub() + } + if specificReturn { + return ret.result1, ret.result2 + } + return fakeReturns.result1, fakeReturns.result2 +} + +func (fake *FakeTokenVerifier) VerifyCallCount() int { + fake.verifyMutex.RLock() + defer fake.verifyMutex.RUnlock() + return len(fake.verifyArgsForCall) +} + +func (fake *FakeTokenVerifier) VerifyCalls(stub func() (*auth.GrantClaims, error)) { + fake.verifyMutex.Lock() + defer fake.verifyMutex.Unlock() + fake.VerifyStub = stub +} + +func (fake *FakeTokenVerifier) VerifyReturns(result1 *auth.GrantClaims, result2 error) { + fake.verifyMutex.Lock() + defer fake.verifyMutex.Unlock() + fake.VerifyStub = nil + fake.verifyReturns = struct { + result1 *auth.GrantClaims + result2 error + }{result1, result2} +} + +func (fake *FakeTokenVerifier) VerifyReturnsOnCall(i int, result1 *auth.GrantClaims, result2 error) { + fake.verifyMutex.Lock() + defer fake.verifyMutex.Unlock() + fake.VerifyStub = nil + if fake.verifyReturnsOnCall == nil { + fake.verifyReturnsOnCall = make(map[int]struct { + result1 *auth.GrantClaims + result2 error + }) + } + fake.verifyReturnsOnCall[i] = struct { + result1 *auth.GrantClaims + result2 error + }{result1, result2} +} + +func (fake *FakeTokenVerifier) Invocations() map[string][][]interface{} { + fake.invocationsMutex.RLock() + defer fake.invocationsMutex.RUnlock() + fake.verifyMutex.RLock() + defer fake.verifyMutex.RUnlock() + copiedInvocations := map[string][][]interface{}{} + for key, value := range fake.invocations { + copiedInvocations[key] = value + } + return copiedInvocations +} + +func (fake *FakeTokenVerifier) recordInvocation(key string, args []interface{}) { + fake.invocationsMutex.Lock() + defer fake.invocationsMutex.Unlock() + if fake.invocations == nil { + fake.invocations = map[string][][]interface{}{} + } + if fake.invocations[key] == nil { + fake.invocations[key] = [][]interface{}{} + } + fake.invocations[key] = append(fake.invocations[key], args) +} + +var _ auth.TokenVerifier = new(FakeTokenVerifier) diff --git a/pkg/auth/grants.go b/pkg/auth/grants.go new file mode 100644 index 000000000..f0adfaffe --- /dev/null +++ b/pkg/auth/grants.go @@ -0,0 +1,7 @@ +package auth + +type GrantClaims struct { + RoomCreate bool `json:"room_create,omitempty"` + RoomJoin bool `json:"room_join,omitempty"` + Room string `json:"room"` +} diff --git a/pkg/auth/interfaces.go b/pkg/auth/interfaces.go new file mode 100644 index 000000000..b306696cc --- /dev/null +++ b/pkg/auth/interfaces.go @@ -0,0 +1,27 @@ +package auth + +import ( + "errors" + "time" +) + +//go:generate go run github.com/maxbrunsfeld/counterfeiter/v6 -generate + +var ( + ErrKeysMissing = errors.New("missing API key or secret key") +) + +//counterfeiter:generate . TokenIssuer +type TokenIssuer interface { + CreateToken(claims *GrantClaims, validFor time.Duration) (string, error) +} + +//counterfeiter:generate . TokenVerifier +type TokenVerifier interface { + Verify() (*GrantClaims, error) +} + +//counterfeiter:generate . KeyProvider +type KeyProvider interface { + GetSecret(key string) string +} diff --git a/pkg/auth/issuer.go b/pkg/auth/issuer.go new file mode 100644 index 000000000..a91a8366f --- /dev/null +++ b/pkg/auth/issuer.go @@ -0,0 +1,41 @@ +package auth + +import ( + "time" + + "gopkg.in/square/go-jose.v2" + "gopkg.in/square/go-jose.v2/jwt" +) + +// Signer that produces token signed with API key and secret +type APIKeyTokenIssuer struct { + APIKey string + SecretKey string +} + +func NewAPIKeyTokenIssuer(key string, secret string) *APIKeyTokenIssuer { + return &APIKeyTokenIssuer{ + APIKey: key, + SecretKey: secret, + } +} + +func (s *APIKeyTokenIssuer) CreateToken(claims *GrantClaims, validFor time.Duration) (string, error) { + if s.APIKey == "" || s.SecretKey == "" { + return "", ErrKeysMissing + } + sig, err := jose.NewSigner(jose.SigningKey{Algorithm: jose.HS256, Key: []byte(s.SecretKey)}, + (&jose.SignerOptions{}).WithType("JWT")) + if err != nil { + return "", err + } + + cl := jwt.Claims{ + Issuer: s.APIKey, + Subject: s.APIKey, + NotBefore: jwt.NewNumericDate(time.Now()), + Expiry: jwt.NewNumericDate(time.Now().Add(validFor)), + } + + return jwt.Signed(sig).Claims(cl).Claims(claims).CompactSerialize() +} diff --git a/pkg/auth/issuer_test.go b/pkg/auth/issuer_test.go new file mode 100644 index 000000000..1d4186234 --- /dev/null +++ b/pkg/auth/issuer_test.go @@ -0,0 +1,47 @@ +package auth_test + +import ( + "strings" + "testing" + "time" + + "github.com/stretchr/testify/assert" + "gopkg.in/square/go-jose.v2/jwt" + + "github.com/livekit/livekit-server/pkg/auth" + "github.com/livekit/livekit-server/pkg/utils" +) + +func TestAPIIssuer(t *testing.T) { + t.Run("keys must be set", func(t *testing.T) { + s := auth.NewAPIKeyTokenIssuer("", "") + _, err := s.CreateToken(&auth.GrantClaims{}, time.Hour) + assert.Equal(t, auth.ErrKeysMissing, err) + }) + + t.Run("generates a decodeable key", func(t *testing.T) { + apiKey, secret := apiKeypair() + //fmt.Println(apiKey, secret) + s := auth.NewAPIKeyTokenIssuer(apiKey, secret) + claims := auth.GrantClaims{RoomJoin: true, Room: "myroom"} + raw, err := s.CreateToken(&claims, time.Hour) + //fmt.Println(raw) + assert.NoError(t, err) + + assert.Len(t, strings.Split(raw, "."), 3) + + // ensure it's a valid JWT + token, err := jwt.ParseSigned(raw) + assert.NoError(t, err) + + decodedGrant := auth.GrantClaims{} + err = token.UnsafeClaimsWithoutVerification(&decodedGrant) + assert.NoError(t, err) + + assert.EqualValues(t, &claims, &decodedGrant) + }) +} + +func apiKeypair() (string, string) { + return utils.NewGuid(utils.APIKeyPrefix), utils.RandomSecret() +} diff --git a/pkg/auth/provider.go b/pkg/auth/provider.go new file mode 100644 index 000000000..3efc9682a --- /dev/null +++ b/pkg/auth/provider.go @@ -0,0 +1,44 @@ +package auth + +import ( + "bufio" + "fmt" + "io" + "log" + "strings" +) + +type FileBasedKeyProvider struct { + keys map[string]string +} + +func NewFileBasedKeyProvider(r io.Reader) (p *FileBasedKeyProvider, err error) { + scanner := bufio.NewScanner(r) + keys := make(map[string]string) + for scanner.Scan() { + line := scanner.Text() + log.Println("line", line) + //break + if len(line) == 0 { + continue + } + parts := strings.Split(string(line), ":") + if len(parts) != 2 { + return nil, fmt.Errorf("invalid api key/secret pair, must be api_key:secret: %v", line) + } + keys[strings.TrimSpace(parts[0])] = strings.TrimSpace(parts[1]) + } + + if err = scanner.Err(); err != nil { + return + } + p = &FileBasedKeyProvider{ + keys: keys, + } + + return +} + +func (p *FileBasedKeyProvider) GetSecret(key string) string { + return p.keys[key] +} diff --git a/pkg/auth/provider_test.go b/pkg/auth/provider_test.go new file mode 100644 index 000000000..c950ba016 --- /dev/null +++ b/pkg/auth/provider_test.go @@ -0,0 +1,40 @@ +package auth_test + +import ( + "io/ioutil" + "os" + "testing" + + "github.com/stretchr/testify/assert" + + "github.com/livekit/livekit-server/pkg/auth" +) + +func TestFileBasedKeyProvider(t *testing.T) { + keys := map[string]string{ + "key1": "secret1", + "key2": "secret2", + "key3": "secret3", + } + f, err := ioutil.TempFile("", "keyfile") + assert.NoError(t, err) + defer func() { + os.Remove(f.Name()) + }() + + f.WriteString("key1:secret1\n") + f.WriteString(" key2: secret2 \r\n") + f.WriteString("\n") + f.WriteString("key3 : secret3") + + f.Close() + + r, err := os.Open(f.Name()) + defer r.Close() + p, err := auth.NewFileBasedKeyProvider(r) + assert.NoError(t, err) + + for key, val := range keys { + assert.Equal(t, val, p.GetSecret(key)) + } +} diff --git a/pkg/auth/verifier.go b/pkg/auth/verifier.go new file mode 100644 index 000000000..fd963962d --- /dev/null +++ b/pkg/auth/verifier.go @@ -0,0 +1,54 @@ +package auth + +import ( + "time" + + "gopkg.in/square/go-jose.v2/jwt" +) + +type APIKeyTokenVerifier struct { + token *jwt.JSONWebToken + apiKey string + secretKey string +} + +func ParseAPIToken(raw string) (*APIKeyTokenVerifier, error) { + tok, err := jwt.ParseSigned(raw) + if err != nil { + return nil, err + } + + out := jwt.Claims{} + if err := tok.UnsafeClaimsWithoutVerification(&out); err != nil { + return nil, err + } + + return &APIKeyTokenVerifier{ + token: tok, + apiKey: out.Issuer, + }, nil +} + +// Returns the API key this token was signed with +func (v *APIKeyTokenVerifier) APIKey() string { + return v.apiKey +} + +func (v *APIKeyTokenVerifier) SetSecretKey(secret string) { + v.secretKey = secret +} + +func (v *APIKeyTokenVerifier) Verify() (*GrantClaims, error) { + if v.secretKey == "" { + return nil, ErrKeysMissing + } + out := jwt.Claims{} + claims := GrantClaims{} + if err := v.token.Claims([]byte(v.secretKey), &out, &claims); err != nil { + return nil, err + } + if err := out.Validate(jwt.Expected{Issuer: v.apiKey, Time: time.Now()}); err != nil { + return nil, err + } + return &claims, nil +} diff --git a/pkg/auth/verifier_test.go b/pkg/auth/verifier_test.go new file mode 100644 index 000000000..0f2d14715 --- /dev/null +++ b/pkg/auth/verifier_test.go @@ -0,0 +1,52 @@ +package auth_test + +import ( + "testing" + "time" + + "github.com/stretchr/testify/assert" + + "github.com/livekit/livekit-server/pkg/auth" +) + +func TestAPIVerifier(t *testing.T) { + apiKey := "APID3B67uxk4Nj2GKiRPibAZ9" + secret := "YHC-CUhbQhGeVCaYgn1BNA++" + accessToken := "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJleHAiOjE2MDg5MzAzMDgsImlzcyI6IkFQSUQzQjY3dXhrNE5qMkdLaVJQaWJBWjkiLCJuYmYiOjE2MDg5MjY3MDgsInJvb21fam9pbiI6dHJ1ZSwicm9vbV9zaWQiOiJteWlkIiwic3ViIjoiQVBJRDNCNjd1eGs0TmoyR0tpUlBpYkFaOSJ9.cmHEBq0MLyRqphmVLM2cLXg5ao5Sro7am8yXhcYKcwE" + t.Run("cannot decode with incorrect key", func(t *testing.T) { + v, err := auth.ParseAPIToken(accessToken) + assert.NoError(t, err) + + assert.Equal(t, apiKey, v.APIKey()) + _, err = v.Verify() + assert.Error(t, err) + + v.SetSecretKey("anothersecret") + _, err = v.Verify() + assert.Error(t, err) + }) + + t.Run("key has expired", func(t *testing.T) { + v, err := auth.ParseAPIToken(accessToken) + v.SetSecretKey(secret) + + _, err = v.Verify() + assert.Error(t, err) + }) + + t.Run("unexpired token is verified", func(t *testing.T) { + s := auth.NewAPIKeyTokenIssuer(apiKey, secret) + claim := auth.GrantClaims{RoomCreate: true} + authToken, err := s.CreateToken(&claim, time.Minute) + assert.NoError(t, err) + + v, err := auth.ParseAPIToken(authToken) + assert.NoError(t, err) + assert.Equal(t, apiKey, v.APIKey()) + + v.SetSecretKey(secret) + decoded, err := v.Verify() + assert.NoError(t, err) + assert.Equal(t, &claim, decoded) + }) +} diff --git a/pkg/rtc/errors.go b/pkg/rtc/errors.go index e1bc58266..17ddec651 100644 --- a/pkg/rtc/errors.go +++ b/pkg/rtc/errors.go @@ -3,5 +3,7 @@ package rtc import "errors" var ( - ErrRoomIdMissing = errors.New("roomId is not set") + ErrRoomIdMissing = errors.New("room is not passed in") + ErrRoomNotFound = errors.New("requested room does not exist") + ErrPermissionDenied = errors.New("no permissions to access the room") ) diff --git a/pkg/rtc/manager.go b/pkg/rtc/manager.go index c007a5ba8..be31e274c 100644 --- a/pkg/rtc/manager.go +++ b/pkg/rtc/manager.go @@ -7,22 +7,25 @@ import ( "github.com/livekit/livekit-server/proto/livekit" ) +// A RoomManager maintains active rooms that are hosted on the current node type RoomManager struct { rtcConf config.RTCConfig externalIP string config WebRTCConfig - rooms map[string]*Room - roomLock sync.RWMutex + rooms map[string]*Room + roomsByName map[string]*Room + roomLock sync.RWMutex } func NewRoomManager(rtcConf config.RTCConfig, externalIP string) (m *RoomManager, err error) { m = &RoomManager{ - rtcConf: rtcConf, - externalIP: externalIP, - rooms: make(map[string]*Room), - roomLock: sync.RWMutex{}, + rtcConf: rtcConf, + externalIP: externalIP, + rooms: make(map[string]*Room), + roomsByName: make(map[string]*Room), + roomLock: sync.RWMutex{}, } wc, err := NewWebRTCConfig(&rtcConf, externalIP) @@ -33,27 +36,53 @@ func NewRoomManager(rtcConf config.RTCConfig, externalIP string) (m *RoomManager return } -func (m *RoomManager) GetRoom(roomId string) *Room { +func (m *RoomManager) GetRoom(idOrName string) *Room { m.roomLock.RLock() defer m.roomLock.RUnlock() - return m.rooms[roomId] + rm := m.rooms[idOrName] + if rm == nil { + rm = m.roomsByName[idOrName] + } + return rm +} + +func (m *RoomManager) GetRoomWithConstraint(idOrName string, onlyName string) (*Room, error) { + if idOrName == "" { + idOrName = onlyName + } + if idOrName == "" { + return nil, ErrRoomIdMissing + } + + rm := m.GetRoom(idOrName) + if rm == nil { + return nil, ErrRoomNotFound + } + + if onlyName != "" && rm.Name != onlyName { + return nil, ErrPermissionDenied + } + return rm, nil } func (m *RoomManager) CreateRoom(req *livekit.CreateRoomRequest) (r *Room, err error) { - r, err = NewRoomForRequest(req, &m.config) - if err != nil { - return - } + r = NewRoomForRequest(req, &m.config) m.roomLock.Lock() defer m.roomLock.Unlock() m.rooms[r.Sid] = r + m.roomsByName[r.Name] = r return } -func (m *RoomManager) DeleteRoom(roomId string) error { +func (m *RoomManager) DeleteRoom(idOrName string) error { + rm := m.GetRoom(idOrName) + if rm == nil { + return nil + } m.roomLock.Lock() defer m.roomLock.Unlock() - delete(m.rooms, roomId) + delete(m.rooms, rm.Sid) + delete(m.roomsByName, rm.Name) return nil } diff --git a/pkg/rtc/manager_test.go b/pkg/rtc/manager_test.go new file mode 100644 index 000000000..b7ca6c9e7 --- /dev/null +++ b/pkg/rtc/manager_test.go @@ -0,0 +1 @@ +package rtc_test diff --git a/pkg/rtc/room.go b/pkg/rtc/room.go index b10d707ad..5cf878312 100644 --- a/pkg/rtc/room.go +++ b/pkg/rtc/room.go @@ -4,7 +4,6 @@ import ( "sync" "time" - "github.com/google/uuid" "github.com/thoas/go-funk" "github.com/livekit/livekit-server/pkg/logger" @@ -22,24 +21,19 @@ type Room struct { //tracks map[string][]Track } -func NewRoomForRequest(req *livekit.CreateRoomRequest, config *WebRTCConfig) (*Room, error) { - id, err := uuid.NewRandom() - if err != nil { - return nil, err - } - +func NewRoomForRequest(req *livekit.CreateRoomRequest, config *WebRTCConfig) *Room { return &Room{ Room: livekit.Room{ Sid: utils.NewGuid(utils.RoomPrefix), + Name: req.Name, EmptyTimeout: req.EmptyTimeout, MaxParticipants: req.MaxParticipants, CreationTime: time.Now().Unix(), - Token: id.String(), }, config: *config, lock: sync.RWMutex{}, participants: make(map[string]Participant), - }, nil + } } func (r *Room) GetParticipant(id string) Participant { @@ -57,9 +51,9 @@ func (r *Room) GetParticipants() []Participant { func (r *Room) ToRoomInfo(node *livekit.Node) *livekit.RoomInfo { return &livekit.RoomInfo{ Sid: r.Sid, + Name: r.Name, NodeIp: node.Ip, CreationTime: r.CreationTime, - Token: r.Token, } } diff --git a/pkg/rtc/room_test.go b/pkg/rtc/room_test.go index e641e7fa4..77931a0b1 100644 --- a/pkg/rtc/room_test.go +++ b/pkg/rtc/room_test.go @@ -15,6 +15,32 @@ const ( numParticipants = 3 ) +func TestNewRoomForRequest(t *testing.T) { + req := &livekit.CreateRoomRequest{ + Name: "myroom", + EmptyTimeout: 120, + MaxParticipants: 50, + } + + rm := rtc.NewRoomForRequest(req, &rtc.WebRTCConfig{}) + assert.NotEmpty(t, rm.Sid) + assert.Equal(t, req.Name, rm.Name) + assert.Equal(t, req.EmptyTimeout, rm.EmptyTimeout) + assert.Equal(t, req.MaxParticipants, rm.MaxParticipants) +} + +func TestToRoomInfo(t *testing.T) { + rm := rtc.NewRoomForRequest(&livekit.CreateRoomRequest{ + Name: "myroom", + EmptyTimeout: 120, + MaxParticipants: 50, + }, &rtc.WebRTCConfig{}) + info := rm.ToRoomInfo(&livekit.Node{Ip: "0.0.0.0"}) + assert.Equal(t, rm.Sid, info.Sid) + assert.Equal(t, rm.Name, info.Name) + assert.Equal(t, "0.0.0.0", info.NodeIp) +} + func TestRoomJoin(t *testing.T) { t.Run("joining returns existing participant data", func(t *testing.T) { rm := newRoomWithParticipants(t, numParticipants) @@ -96,10 +122,7 @@ func TestNewTrack(t *testing.T) { } func newRoomWithParticipants(t *testing.T, num int) *rtc.Room { - rm, err := rtc.NewRoomForRequest(&livekit.CreateRoomRequest{}, &rtc.WebRTCConfig{}) - if err != nil { - panic("could not create a room") - } + rm := rtc.NewRoomForRequest(&livekit.CreateRoomRequest{}, &rtc.WebRTCConfig{}) for i := 0; i < num; i++ { participant := newMockParticipant("") err := rm.Join(participant) diff --git a/pkg/service/auth.go b/pkg/service/auth.go new file mode 100644 index 000000000..541d76803 --- /dev/null +++ b/pkg/service/auth.go @@ -0,0 +1,126 @@ +package service + +import ( + "context" + "errors" + "net/http" + "strings" + + "github.com/twitchtv/twirp" + + "github.com/livekit/livekit-server/pkg/auth" +) + +const ( + authorizationHeader = "Authorization" + bearerPrefix = "Bearer " + grantsKey = "grants" +) + +var ( + ErrPermissionDenied = errors.New("permissions denied") + AuthRequired bool +) + +// authentication middleware +type APIKeyAuthMiddleware struct { + provider auth.KeyProvider +} + +func NewAPIKeyAuthMiddleware(provider auth.KeyProvider) *APIKeyAuthMiddleware { + return &APIKeyAuthMiddleware{ + provider: provider, + } +} + +func (m *APIKeyAuthMiddleware) ServeHTTP(w http.ResponseWriter, r *http.Request, next http.HandlerFunc) { + authHeader := r.Header.Get(authorizationHeader) + + if authHeader != "" { + if !strings.HasPrefix(authHeader, bearerPrefix) { + w.WriteHeader(http.StatusUnauthorized) + w.Write([]byte("invalid authorization header. Must start with " + bearerPrefix)) + return + } + + authToken := authHeader[len(bearerPrefix):] + v, err := auth.ParseAPIToken(authToken) + if err != nil { + w.WriteHeader(http.StatusUnauthorized) + w.Write([]byte("invalid authorization token")) + return + } + + secret := m.provider.GetSecret(v.APIKey()) + if secret == "" { + w.WriteHeader(http.StatusUnauthorized) + w.Write([]byte("invalid API key")) + return + } + + v.SetSecretKey(secret) + + grants, err := v.Verify() + if err != nil { + w.WriteHeader(http.StatusUnauthorized) + w.Write([]byte("invalid token: " + err.Error())) + return + } + + // set grants in context + ctx := r.Context() + r = r.WithContext(context.WithValue(ctx, grantsKey, grants)) + } + + next.ServeHTTP(w, r) +} + +func GetGrants(ctx context.Context) *auth.GrantClaims { + claims, ok := ctx.Value(grantsKey).(*auth.GrantClaims) + if !ok { + return nil + } + return claims +} + +func SetAuthorizationToken(r *http.Request, token string) { + r.Header.Set(authorizationHeader, bearerPrefix+token) +} + +func EnsureJoinPermission(ctx context.Context) (name string, err error) { + if !AuthRequired { + return "", nil + } + claims := GetGrants(ctx) + if claims == nil { + err = ErrPermissionDenied + return + } + + if claims.RoomJoin { + name = claims.Room + } else { + err = ErrPermissionDenied + } + return +} + +func EnsureCreatePermission(ctx context.Context) error { + if !AuthRequired { + return nil + } + claims := GetGrants(ctx) + if claims == nil { + return ErrPermissionDenied + } + + if claims.RoomCreate { + return nil + } + return ErrPermissionDenied +} + +// wraps authentication errors around Twirp +func twirpAuthError(err error) error { + return twirp.NewError(twirp.Unauthenticated, err.Error()) +} diff --git a/pkg/service/auth_test.go b/pkg/service/auth_test.go new file mode 100644 index 000000000..c339b23b5 --- /dev/null +++ b/pkg/service/auth_test.go @@ -0,0 +1,59 @@ +package service_test + +import ( + "net/http" + "net/http/httptest" + "testing" + "time" + + "github.com/stretchr/testify/assert" + + "github.com/livekit/livekit-server/pkg/auth" + "github.com/livekit/livekit-server/pkg/auth/authfakes" + "github.com/livekit/livekit-server/pkg/service" +) + +func TestAuthMiddleware(t *testing.T) { + api := "APIabcdefg" + secret := "somesecretencodedinbase62" + provider := &authfakes.FakeKeyProvider{} + provider.GetSecretReturns(secret) + + m := service.NewAPIKeyAuthMiddleware(provider) + var grants *auth.GrantClaims + handler := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + grants = service.GetGrants(r.Context()) + w.WriteHeader(http.StatusOK) + }) + + // ensure that the original claim could be retrieved + issuer := auth.NewAPIKeyTokenIssuer(api, secret) + orig := &auth.GrantClaims{Room: "abcdefg", RoomJoin: true} + token, err := issuer.CreateToken(orig, time.Minute) + assert.NoError(t, err) + + r := &http.Request{Header: http.Header{}} + w := httptest.NewRecorder() + service.SetAuthorizationToken(r, token) + m.ServeHTTP(w, r, handler) + + assert.NotNil(t, grants) + assert.EqualValues(t, orig, grants) + + // no authorization == no claims + grants = nil + w = httptest.NewRecorder() + r = &http.Request{Header: http.Header{}} + m.ServeHTTP(w, r, handler) + assert.Nil(t, grants) + assert.Equal(t, http.StatusOK, w.Code) + + // incorrect authorization: error + grants = nil + w = httptest.NewRecorder() + r = &http.Request{Header: http.Header{}} + service.SetAuthorizationToken(r, "invalid token") + m.ServeHTTP(w, r, handler) + assert.Nil(t, grants) + assert.Equal(t, http.StatusUnauthorized, w.Code) +} diff --git a/pkg/service/rtc.go b/pkg/service/rtc.go index d3f218a7c..3b2d3f266 100644 --- a/pkg/service/rtc.go +++ b/pkg/service/rtc.go @@ -15,9 +15,8 @@ import ( ) type RTCService struct { - skipTokenCheck bool - manager *rtc.RoomManager - upgrader websocket.Upgrader + manager *rtc.RoomManager + upgrader websocket.Upgrader } func NewRTCService(conf *config.Config, manager *rtc.RoomManager) *RTCService { @@ -27,7 +26,6 @@ func NewRTCService(conf *config.Config, manager *rtc.RoomManager) *RTCService { } if conf.Development { - s.skipTokenCheck = true s.upgrader.CheckOrigin = func(r *http.Request) bool { // allow all in dev return true @@ -39,18 +37,19 @@ func NewRTCService(conf *config.Config, manager *rtc.RoomManager) *RTCService { func (s *RTCService) ServeHTTP(w http.ResponseWriter, r *http.Request) { roomId := r.FormValue("room_id") - token := r.FormValue("token") pName := r.FormValue("name") log := logger.GetLogger() - room := s.manager.GetRoom(roomId) - if room == nil { - writeJSONError(w, http.StatusNotFound, "room not found") + onlyName, err := EnsureJoinPermission(r.Context()) + if err != nil { + writeJSONError(w, http.StatusUnauthorized, err.Error()) return } - if !s.skipTokenCheck && room.Token != token { - writeJSONError(w, http.StatusUnauthorized, "invalid room token") + room, err := s.manager.GetRoomWithConstraint(roomId, onlyName) + if err != nil { + // TODO: return errors/status correctly + writeJSONError(w, http.StatusNotFound, err.Error()) return } diff --git a/pkg/service/simpleroom.go b/pkg/service/simpleroom.go index 1738b5048..36941e6e5 100644 --- a/pkg/service/simpleroom.go +++ b/pkg/service/simpleroom.go @@ -27,6 +27,9 @@ func NewSimpleRoomService(manager *rtc.RoomManager, localNode *node.Node) (svc * } func (s *SimpleRoomService) CreateRoom(ctx context.Context, req *livekit.CreateRoomRequest) (res *livekit.RoomInfo, err error) { + if err = EnsureCreatePermission(ctx); err != nil { + return nil, twirpAuthError(err) + } room, err := s.manager.CreateRoom(req) if err != nil { return @@ -37,9 +40,14 @@ func (s *SimpleRoomService) CreateRoom(ctx context.Context, req *livekit.CreateR } func (s *SimpleRoomService) GetRoom(ctx context.Context, req *livekit.GetRoomRequest) (res *livekit.RoomInfo, err error) { - room := s.manager.GetRoom(req.RoomId) - if room == nil { - err = twirp.NewError(twirp.NotFound, "room does not exist") + onlyName, err := EnsureJoinPermission(ctx) + if err != nil { + return nil, twirpAuthError(err) + } + + room, err := s.manager.GetRoomWithConstraint(req.Room, onlyName) + if err != nil { + // TODO: translate error codes to twirp return } @@ -48,7 +56,10 @@ func (s *SimpleRoomService) GetRoom(ctx context.Context, req *livekit.GetRoomReq } func (s *SimpleRoomService) DeleteRoom(ctx context.Context, req *livekit.DeleteRoomRequest) (res *livekit.DeleteRoomResponse, err error) { - err = s.manager.DeleteRoom(req.RoomId) + if err = EnsureCreatePermission(ctx); err != nil { + return nil, twirpAuthError(err) + } + err = s.manager.DeleteRoom(req.Room) if err != nil { err = twirp.WrapError(twirp.InternalError("could not delete room"), err) return diff --git a/pkg/utils/id.go b/pkg/utils/id.go index af2e5be06..debca8ec5 100644 --- a/pkg/utils/id.go +++ b/pkg/utils/id.go @@ -9,6 +9,7 @@ const ( NodePrefix = "ND_" ParticipantPrefix = "PA_" TrackPrefix = "TR_" + APIKeyPrefix = "API" ) func NewGuid(prefix string) string { diff --git a/pkg/utils/secret.go b/pkg/utils/secret.go new file mode 100644 index 000000000..0316fbbe6 --- /dev/null +++ b/pkg/utils/secret.go @@ -0,0 +1,12 @@ +package utils + +import ( + "github.com/google/uuid" + "github.com/lytics/base62" +) + +func RandomSecret() string { + // cannot error + bin, _ := uuid.New().MarshalBinary() + return base62.StdEncoding.EncodeToString(bin) +} diff --git a/proto/livekit/model.pb.go b/proto/livekit/model.pb.go index 62c8cc9d7..a7a10424f 100644 --- a/proto/livekit/model.pb.go +++ b/proto/livekit/model.pb.go @@ -28,7 +28,7 @@ const _ = proto.ProtoPackageIsVersion4 type ParticipantInfo_State int32 const ( - // websocket connected, but not offered yet + // websocket' connected, but not offered yet ParticipantInfo_JOINING ParticipantInfo_State = 0 // server received client offer ParticipantInfo_JOINED ParticipantInfo_State = 1 @@ -263,10 +263,10 @@ type Room struct { unknownFields protoimpl.UnknownFields Sid string `protobuf:"bytes,1,opt,name=sid,proto3" json:"sid,omitempty"` - EmptyTimeout uint32 `protobuf:"varint,2,opt,name=empty_timeout,json=emptyTimeout,proto3" json:"empty_timeout,omitempty"` - MaxParticipants uint32 `protobuf:"varint,3,opt,name=max_participants,json=maxParticipants,proto3" json:"max_participants,omitempty"` - CreationTime int64 `protobuf:"varint,4,opt,name=creation_time,json=creationTime,proto3" json:"creation_time,omitempty"` - Token string `protobuf:"bytes,5,opt,name=token,proto3" json:"token,omitempty"` + Name string `protobuf:"bytes,2,opt,name=name,proto3" json:"name,omitempty"` + EmptyTimeout uint32 `protobuf:"varint,3,opt,name=empty_timeout,json=emptyTimeout,proto3" json:"empty_timeout,omitempty"` + MaxParticipants uint32 `protobuf:"varint,4,opt,name=max_participants,json=maxParticipants,proto3" json:"max_participants,omitempty"` + CreationTime int64 `protobuf:"varint,5,opt,name=creation_time,json=creationTime,proto3" json:"creation_time,omitempty"` } func (x *Room) Reset() { @@ -308,6 +308,13 @@ func (x *Room) GetSid() string { return "" } +func (x *Room) GetName() string { + if x != nil { + return x.Name + } + return "" +} + func (x *Room) GetEmptyTimeout() uint32 { if x != nil { return x.EmptyTimeout @@ -329,22 +336,15 @@ func (x *Room) GetCreationTime() int64 { return 0 } -func (x *Room) GetToken() string { - if x != nil { - return x.Token - } - return "" -} - type RoomInfo struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache unknownFields protoimpl.UnknownFields Sid string `protobuf:"bytes,1,opt,name=sid,proto3" json:"sid,omitempty"` - NodeIp string `protobuf:"bytes,2,opt,name=node_ip,json=nodeIp,proto3" json:"node_ip,omitempty"` - CreationTime int64 `protobuf:"varint,3,opt,name=creation_time,json=creationTime,proto3" json:"creation_time,omitempty"` - Token string `protobuf:"bytes,4,opt,name=token,proto3" json:"token,omitempty"` + Name string `protobuf:"bytes,2,opt,name=name,proto3" json:"name,omitempty"` + NodeIp string `protobuf:"bytes,3,opt,name=node_ip,json=nodeIp,proto3" json:"node_ip,omitempty"` + CreationTime int64 `protobuf:"varint,4,opt,name=creation_time,json=creationTime,proto3" json:"creation_time,omitempty"` } func (x *RoomInfo) Reset() { @@ -386,6 +386,13 @@ func (x *RoomInfo) GetSid() string { return "" } +func (x *RoomInfo) GetName() string { + if x != nil { + return x.Name + } + return "" +} + func (x *RoomInfo) GetNodeIp() string { if x != nil { return x.NodeIp @@ -400,13 +407,6 @@ func (x *RoomInfo) GetCreationTime() int64 { return 0 } -func (x *RoomInfo) GetToken() string { - if x != nil { - return x.Token - } - return "" -} - type ParticipantInfo struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache @@ -637,55 +637,55 @@ var file_model_proto_rawDesc = []byte{ 0x12, 0x1b, 0x0a, 0x09, 0x6e, 0x75, 0x6d, 0x5f, 0x72, 0x6f, 0x6f, 0x6d, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x05, 0x52, 0x08, 0x6e, 0x75, 0x6d, 0x52, 0x6f, 0x6f, 0x6d, 0x73, 0x12, 0x1f, 0x0a, 0x0b, 0x6e, 0x75, 0x6d, 0x5f, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x73, 0x18, 0x02, 0x20, 0x01, - 0x28, 0x05, 0x52, 0x0a, 0x6e, 0x75, 0x6d, 0x43, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x73, 0x22, 0xa3, + 0x28, 0x05, 0x52, 0x0a, 0x6e, 0x75, 0x6d, 0x43, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x73, 0x22, 0xa1, 0x01, 0x0a, 0x04, 0x52, 0x6f, 0x6f, 0x6d, 0x12, 0x10, 0x0a, 0x03, 0x73, 0x69, 0x64, 0x18, 0x01, - 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x73, 0x69, 0x64, 0x12, 0x23, 0x0a, 0x0d, 0x65, 0x6d, 0x70, - 0x74, 0x79, 0x5f, 0x74, 0x69, 0x6d, 0x65, 0x6f, 0x75, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0d, - 0x52, 0x0c, 0x65, 0x6d, 0x70, 0x74, 0x79, 0x54, 0x69, 0x6d, 0x65, 0x6f, 0x75, 0x74, 0x12, 0x29, - 0x0a, 0x10, 0x6d, 0x61, 0x78, 0x5f, 0x70, 0x61, 0x72, 0x74, 0x69, 0x63, 0x69, 0x70, 0x61, 0x6e, - 0x74, 0x73, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x0f, 0x6d, 0x61, 0x78, 0x50, 0x61, 0x72, - 0x74, 0x69, 0x63, 0x69, 0x70, 0x61, 0x6e, 0x74, 0x73, 0x12, 0x23, 0x0a, 0x0d, 0x63, 0x72, 0x65, - 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x74, 0x69, 0x6d, 0x65, 0x18, 0x04, 0x20, 0x01, 0x28, 0x03, - 0x52, 0x0c, 0x63, 0x72, 0x65, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x54, 0x69, 0x6d, 0x65, 0x12, 0x14, - 0x0a, 0x05, 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x74, - 0x6f, 0x6b, 0x65, 0x6e, 0x22, 0x70, 0x0a, 0x08, 0x52, 0x6f, 0x6f, 0x6d, 0x49, 0x6e, 0x66, 0x6f, - 0x12, 0x10, 0x0a, 0x03, 0x73, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x73, - 0x69, 0x64, 0x12, 0x17, 0x0a, 0x07, 0x6e, 0x6f, 0x64, 0x65, 0x5f, 0x69, 0x70, 0x18, 0x02, 0x20, - 0x01, 0x28, 0x09, 0x52, 0x06, 0x6e, 0x6f, 0x64, 0x65, 0x49, 0x70, 0x12, 0x23, 0x0a, 0x0d, 0x63, - 0x72, 0x65, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x74, 0x69, 0x6d, 0x65, 0x18, 0x03, 0x20, 0x01, - 0x28, 0x03, 0x52, 0x0c, 0x63, 0x72, 0x65, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x54, 0x69, 0x6d, 0x65, - 0x12, 0x14, 0x0a, 0x05, 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, - 0x05, 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x22, 0xd9, 0x01, 0x0a, 0x0f, 0x50, 0x61, 0x72, 0x74, 0x69, - 0x63, 0x69, 0x70, 0x61, 0x6e, 0x74, 0x49, 0x6e, 0x66, 0x6f, 0x12, 0x10, 0x0a, 0x03, 0x73, 0x69, - 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x73, 0x69, 0x64, 0x12, 0x12, 0x0a, 0x04, - 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, - 0x12, 0x34, 0x0a, 0x05, 0x73, 0x74, 0x61, 0x74, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0e, 0x32, - 0x1e, 0x2e, 0x6c, 0x69, 0x76, 0x65, 0x6b, 0x69, 0x74, 0x2e, 0x50, 0x61, 0x72, 0x74, 0x69, 0x63, - 0x69, 0x70, 0x61, 0x6e, 0x74, 0x49, 0x6e, 0x66, 0x6f, 0x2e, 0x53, 0x74, 0x61, 0x74, 0x65, 0x52, - 0x05, 0x73, 0x74, 0x61, 0x74, 0x65, 0x12, 0x2a, 0x0a, 0x06, 0x74, 0x72, 0x61, 0x63, 0x6b, 0x73, - 0x18, 0x04, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x12, 0x2e, 0x6c, 0x69, 0x76, 0x65, 0x6b, 0x69, 0x74, - 0x2e, 0x54, 0x72, 0x61, 0x63, 0x6b, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x06, 0x74, 0x72, 0x61, 0x63, - 0x6b, 0x73, 0x22, 0x3e, 0x0a, 0x05, 0x53, 0x74, 0x61, 0x74, 0x65, 0x12, 0x0b, 0x0a, 0x07, 0x4a, - 0x4f, 0x49, 0x4e, 0x49, 0x4e, 0x47, 0x10, 0x00, 0x12, 0x0a, 0x0a, 0x06, 0x4a, 0x4f, 0x49, 0x4e, - 0x45, 0x44, 0x10, 0x01, 0x12, 0x0a, 0x0a, 0x06, 0x41, 0x43, 0x54, 0x49, 0x56, 0x45, 0x10, 0x02, - 0x12, 0x10, 0x0a, 0x0c, 0x44, 0x49, 0x53, 0x43, 0x4f, 0x4e, 0x4e, 0x45, 0x43, 0x54, 0x45, 0x44, - 0x10, 0x03, 0x22, 0x86, 0x01, 0x0a, 0x09, 0x54, 0x72, 0x61, 0x63, 0x6b, 0x49, 0x6e, 0x66, 0x6f, - 0x12, 0x10, 0x0a, 0x03, 0x73, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x73, - 0x69, 0x64, 0x12, 0x2b, 0x0a, 0x04, 0x74, 0x79, 0x70, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0e, - 0x32, 0x17, 0x2e, 0x6c, 0x69, 0x76, 0x65, 0x6b, 0x69, 0x74, 0x2e, 0x54, 0x72, 0x61, 0x63, 0x6b, - 0x49, 0x6e, 0x66, 0x6f, 0x2e, 0x54, 0x79, 0x70, 0x65, 0x52, 0x04, 0x74, 0x79, 0x70, 0x65, 0x12, - 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, - 0x61, 0x6d, 0x65, 0x22, 0x26, 0x0a, 0x04, 0x54, 0x79, 0x70, 0x65, 0x12, 0x09, 0x0a, 0x05, 0x41, - 0x55, 0x44, 0x49, 0x4f, 0x10, 0x00, 0x12, 0x09, 0x0a, 0x05, 0x56, 0x49, 0x44, 0x45, 0x4f, 0x10, - 0x01, 0x12, 0x08, 0x0a, 0x04, 0x44, 0x41, 0x54, 0x41, 0x10, 0x02, 0x22, 0x46, 0x0a, 0x0b, 0x44, - 0x61, 0x74, 0x61, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x14, 0x0a, 0x04, 0x74, 0x65, - 0x78, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x48, 0x00, 0x52, 0x04, 0x74, 0x65, 0x78, 0x74, - 0x12, 0x18, 0x0a, 0x06, 0x62, 0x69, 0x6e, 0x61, 0x72, 0x79, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0c, - 0x48, 0x00, 0x52, 0x06, 0x62, 0x69, 0x6e, 0x61, 0x72, 0x79, 0x42, 0x07, 0x0a, 0x05, 0x76, 0x61, - 0x6c, 0x75, 0x65, 0x42, 0x31, 0x5a, 0x2f, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, - 0x6d, 0x2f, 0x6c, 0x69, 0x76, 0x65, 0x6b, 0x69, 0x74, 0x2f, 0x6c, 0x69, 0x76, 0x65, 0x6b, 0x69, - 0x74, 0x2d, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2f, 0x6c, - 0x69, 0x76, 0x65, 0x6b, 0x69, 0x74, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, + 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x73, 0x69, 0x64, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, + 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x23, 0x0a, + 0x0d, 0x65, 0x6d, 0x70, 0x74, 0x79, 0x5f, 0x74, 0x69, 0x6d, 0x65, 0x6f, 0x75, 0x74, 0x18, 0x03, + 0x20, 0x01, 0x28, 0x0d, 0x52, 0x0c, 0x65, 0x6d, 0x70, 0x74, 0x79, 0x54, 0x69, 0x6d, 0x65, 0x6f, + 0x75, 0x74, 0x12, 0x29, 0x0a, 0x10, 0x6d, 0x61, 0x78, 0x5f, 0x70, 0x61, 0x72, 0x74, 0x69, 0x63, + 0x69, 0x70, 0x61, 0x6e, 0x74, 0x73, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x0f, 0x6d, 0x61, + 0x78, 0x50, 0x61, 0x72, 0x74, 0x69, 0x63, 0x69, 0x70, 0x61, 0x6e, 0x74, 0x73, 0x12, 0x23, 0x0a, + 0x0d, 0x63, 0x72, 0x65, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x74, 0x69, 0x6d, 0x65, 0x18, 0x05, + 0x20, 0x01, 0x28, 0x03, 0x52, 0x0c, 0x63, 0x72, 0x65, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x54, 0x69, + 0x6d, 0x65, 0x22, 0x6e, 0x0a, 0x08, 0x52, 0x6f, 0x6f, 0x6d, 0x49, 0x6e, 0x66, 0x6f, 0x12, 0x10, + 0x0a, 0x03, 0x73, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x73, 0x69, 0x64, + 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, + 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x17, 0x0a, 0x07, 0x6e, 0x6f, 0x64, 0x65, 0x5f, 0x69, 0x70, 0x18, + 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x6e, 0x6f, 0x64, 0x65, 0x49, 0x70, 0x12, 0x23, 0x0a, + 0x0d, 0x63, 0x72, 0x65, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x74, 0x69, 0x6d, 0x65, 0x18, 0x04, + 0x20, 0x01, 0x28, 0x03, 0x52, 0x0c, 0x63, 0x72, 0x65, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x54, 0x69, + 0x6d, 0x65, 0x22, 0xd9, 0x01, 0x0a, 0x0f, 0x50, 0x61, 0x72, 0x74, 0x69, 0x63, 0x69, 0x70, 0x61, + 0x6e, 0x74, 0x49, 0x6e, 0x66, 0x6f, 0x12, 0x10, 0x0a, 0x03, 0x73, 0x69, 0x64, 0x18, 0x01, 0x20, + 0x01, 0x28, 0x09, 0x52, 0x03, 0x73, 0x69, 0x64, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, + 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x34, 0x0a, 0x05, + 0x73, 0x74, 0x61, 0x74, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x1e, 0x2e, 0x6c, 0x69, + 0x76, 0x65, 0x6b, 0x69, 0x74, 0x2e, 0x50, 0x61, 0x72, 0x74, 0x69, 0x63, 0x69, 0x70, 0x61, 0x6e, + 0x74, 0x49, 0x6e, 0x66, 0x6f, 0x2e, 0x53, 0x74, 0x61, 0x74, 0x65, 0x52, 0x05, 0x73, 0x74, 0x61, + 0x74, 0x65, 0x12, 0x2a, 0x0a, 0x06, 0x74, 0x72, 0x61, 0x63, 0x6b, 0x73, 0x18, 0x04, 0x20, 0x03, + 0x28, 0x0b, 0x32, 0x12, 0x2e, 0x6c, 0x69, 0x76, 0x65, 0x6b, 0x69, 0x74, 0x2e, 0x54, 0x72, 0x61, + 0x63, 0x6b, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x06, 0x74, 0x72, 0x61, 0x63, 0x6b, 0x73, 0x22, 0x3e, + 0x0a, 0x05, 0x53, 0x74, 0x61, 0x74, 0x65, 0x12, 0x0b, 0x0a, 0x07, 0x4a, 0x4f, 0x49, 0x4e, 0x49, + 0x4e, 0x47, 0x10, 0x00, 0x12, 0x0a, 0x0a, 0x06, 0x4a, 0x4f, 0x49, 0x4e, 0x45, 0x44, 0x10, 0x01, + 0x12, 0x0a, 0x0a, 0x06, 0x41, 0x43, 0x54, 0x49, 0x56, 0x45, 0x10, 0x02, 0x12, 0x10, 0x0a, 0x0c, + 0x44, 0x49, 0x53, 0x43, 0x4f, 0x4e, 0x4e, 0x45, 0x43, 0x54, 0x45, 0x44, 0x10, 0x03, 0x22, 0x86, + 0x01, 0x0a, 0x09, 0x54, 0x72, 0x61, 0x63, 0x6b, 0x49, 0x6e, 0x66, 0x6f, 0x12, 0x10, 0x0a, 0x03, + 0x73, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x73, 0x69, 0x64, 0x12, 0x2b, + 0x0a, 0x04, 0x74, 0x79, 0x70, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x17, 0x2e, 0x6c, + 0x69, 0x76, 0x65, 0x6b, 0x69, 0x74, 0x2e, 0x54, 0x72, 0x61, 0x63, 0x6b, 0x49, 0x6e, 0x66, 0x6f, + 0x2e, 0x54, 0x79, 0x70, 0x65, 0x52, 0x04, 0x74, 0x79, 0x70, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x6e, + 0x61, 0x6d, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x22, + 0x26, 0x0a, 0x04, 0x54, 0x79, 0x70, 0x65, 0x12, 0x09, 0x0a, 0x05, 0x41, 0x55, 0x44, 0x49, 0x4f, + 0x10, 0x00, 0x12, 0x09, 0x0a, 0x05, 0x56, 0x49, 0x44, 0x45, 0x4f, 0x10, 0x01, 0x12, 0x08, 0x0a, + 0x04, 0x44, 0x41, 0x54, 0x41, 0x10, 0x02, 0x22, 0x46, 0x0a, 0x0b, 0x44, 0x61, 0x74, 0x61, 0x4d, + 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x14, 0x0a, 0x04, 0x74, 0x65, 0x78, 0x74, 0x18, 0x01, + 0x20, 0x01, 0x28, 0x09, 0x48, 0x00, 0x52, 0x04, 0x74, 0x65, 0x78, 0x74, 0x12, 0x18, 0x0a, 0x06, + 0x62, 0x69, 0x6e, 0x61, 0x72, 0x79, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0c, 0x48, 0x00, 0x52, 0x06, + 0x62, 0x69, 0x6e, 0x61, 0x72, 0x79, 0x42, 0x07, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x42, + 0x31, 0x5a, 0x2f, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x6c, 0x69, + 0x76, 0x65, 0x6b, 0x69, 0x74, 0x2f, 0x6c, 0x69, 0x76, 0x65, 0x6b, 0x69, 0x74, 0x2d, 0x73, 0x65, + 0x72, 0x76, 0x65, 0x72, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2f, 0x6c, 0x69, 0x76, 0x65, 0x6b, + 0x69, 0x74, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, } var ( diff --git a/proto/livekit/room.pb.go b/proto/livekit/room.pb.go index 6c3a52346..ee25fcfd0 100644 --- a/proto/livekit/room.pb.go +++ b/proto/livekit/room.pb.go @@ -30,9 +30,10 @@ type CreateRoomRequest struct { sizeCache protoimpl.SizeCache unknownFields protoimpl.UnknownFields + Name string `protobuf:"bytes,1,opt,name=name,proto3" json:"name,omitempty"` // number of seconds the room should cleanup after being empty - EmptyTimeout uint32 `protobuf:"varint,1,opt,name=empty_timeout,json=emptyTimeout,proto3" json:"empty_timeout,omitempty"` - MaxParticipants uint32 `protobuf:"varint,2,opt,name=max_participants,json=maxParticipants,proto3" json:"max_participants,omitempty"` + EmptyTimeout uint32 `protobuf:"varint,2,opt,name=empty_timeout,json=emptyTimeout,proto3" json:"empty_timeout,omitempty"` + MaxParticipants uint32 `protobuf:"varint,3,opt,name=max_participants,json=maxParticipants,proto3" json:"max_participants,omitempty"` } func (x *CreateRoomRequest) Reset() { @@ -67,6 +68,13 @@ func (*CreateRoomRequest) Descriptor() ([]byte, []int) { return file_room_proto_rawDescGZIP(), []int{0} } +func (x *CreateRoomRequest) GetName() string { + if x != nil { + return x.Name + } + return "" +} + func (x *CreateRoomRequest) GetEmptyTimeout() uint32 { if x != nil { return x.EmptyTimeout @@ -86,7 +94,7 @@ type GetRoomRequest struct { sizeCache protoimpl.SizeCache unknownFields protoimpl.UnknownFields - RoomId string `protobuf:"bytes,1,opt,name=room_id,json=roomId,proto3" json:"room_id,omitempty"` + Room string `protobuf:"bytes,1,opt,name=room,proto3" json:"room,omitempty"` } func (x *GetRoomRequest) Reset() { @@ -121,9 +129,9 @@ func (*GetRoomRequest) Descriptor() ([]byte, []int) { return file_room_proto_rawDescGZIP(), []int{1} } -func (x *GetRoomRequest) GetRoomId() string { +func (x *GetRoomRequest) GetRoom() string { if x != nil { - return x.RoomId + return x.Room } return "" } @@ -133,7 +141,7 @@ type DeleteRoomRequest struct { sizeCache protoimpl.SizeCache unknownFields protoimpl.UnknownFields - RoomId string `protobuf:"bytes,1,opt,name=room_id,json=roomId,proto3" json:"room_id,omitempty"` + Room string `protobuf:"bytes,1,opt,name=room,proto3" json:"room,omitempty"` } func (x *DeleteRoomRequest) Reset() { @@ -168,9 +176,9 @@ func (*DeleteRoomRequest) Descriptor() ([]byte, []int) { return file_room_proto_rawDescGZIP(), []int{2} } -func (x *DeleteRoomRequest) GetRoomId() string { +func (x *DeleteRoomRequest) GetRoom() string { if x != nil { - return x.RoomId + return x.Room } return "" } @@ -218,36 +226,37 @@ var File_room_proto protoreflect.FileDescriptor var file_room_proto_rawDesc = []byte{ 0x0a, 0x0a, 0x72, 0x6f, 0x6f, 0x6d, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x07, 0x6c, 0x69, 0x76, 0x65, 0x6b, 0x69, 0x74, 0x1a, 0x0b, 0x6d, 0x6f, 0x64, 0x65, 0x6c, 0x2e, 0x70, 0x72, 0x6f, - 0x74, 0x6f, 0x22, 0x63, 0x0a, 0x11, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x52, 0x6f, 0x6f, 0x6d, - 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x23, 0x0a, 0x0d, 0x65, 0x6d, 0x70, 0x74, 0x79, - 0x5f, 0x74, 0x69, 0x6d, 0x65, 0x6f, 0x75, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x0c, - 0x65, 0x6d, 0x70, 0x74, 0x79, 0x54, 0x69, 0x6d, 0x65, 0x6f, 0x75, 0x74, 0x12, 0x29, 0x0a, 0x10, - 0x6d, 0x61, 0x78, 0x5f, 0x70, 0x61, 0x72, 0x74, 0x69, 0x63, 0x69, 0x70, 0x61, 0x6e, 0x74, 0x73, - 0x18, 0x02, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x0f, 0x6d, 0x61, 0x78, 0x50, 0x61, 0x72, 0x74, 0x69, - 0x63, 0x69, 0x70, 0x61, 0x6e, 0x74, 0x73, 0x22, 0x29, 0x0a, 0x0e, 0x47, 0x65, 0x74, 0x52, 0x6f, - 0x6f, 0x6d, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x17, 0x0a, 0x07, 0x72, 0x6f, 0x6f, - 0x6d, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x72, 0x6f, 0x6f, 0x6d, - 0x49, 0x64, 0x22, 0x2c, 0x0a, 0x11, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x52, 0x6f, 0x6f, 0x6d, - 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x17, 0x0a, 0x07, 0x72, 0x6f, 0x6f, 0x6d, 0x5f, - 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x72, 0x6f, 0x6f, 0x6d, 0x49, 0x64, - 0x22, 0x14, 0x0a, 0x12, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x52, 0x6f, 0x6f, 0x6d, 0x52, 0x65, - 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x32, 0xc8, 0x01, 0x0a, 0x0b, 0x52, 0x6f, 0x6f, 0x6d, 0x53, - 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x12, 0x3b, 0x0a, 0x0a, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, - 0x52, 0x6f, 0x6f, 0x6d, 0x12, 0x1a, 0x2e, 0x6c, 0x69, 0x76, 0x65, 0x6b, 0x69, 0x74, 0x2e, 0x43, - 0x72, 0x65, 0x61, 0x74, 0x65, 0x52, 0x6f, 0x6f, 0x6d, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, - 0x1a, 0x11, 0x2e, 0x6c, 0x69, 0x76, 0x65, 0x6b, 0x69, 0x74, 0x2e, 0x52, 0x6f, 0x6f, 0x6d, 0x49, - 0x6e, 0x66, 0x6f, 0x12, 0x35, 0x0a, 0x07, 0x47, 0x65, 0x74, 0x52, 0x6f, 0x6f, 0x6d, 0x12, 0x17, - 0x2e, 0x6c, 0x69, 0x76, 0x65, 0x6b, 0x69, 0x74, 0x2e, 0x47, 0x65, 0x74, 0x52, 0x6f, 0x6f, 0x6d, - 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x11, 0x2e, 0x6c, 0x69, 0x76, 0x65, 0x6b, 0x69, - 0x74, 0x2e, 0x52, 0x6f, 0x6f, 0x6d, 0x49, 0x6e, 0x66, 0x6f, 0x12, 0x45, 0x0a, 0x0a, 0x44, 0x65, - 0x6c, 0x65, 0x74, 0x65, 0x52, 0x6f, 0x6f, 0x6d, 0x12, 0x1a, 0x2e, 0x6c, 0x69, 0x76, 0x65, 0x6b, - 0x69, 0x74, 0x2e, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x52, 0x6f, 0x6f, 0x6d, 0x52, 0x65, 0x71, - 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1b, 0x2e, 0x6c, 0x69, 0x76, 0x65, 0x6b, 0x69, 0x74, 0x2e, 0x44, - 0x65, 0x6c, 0x65, 0x74, 0x65, 0x52, 0x6f, 0x6f, 0x6d, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, - 0x65, 0x42, 0x31, 0x5a, 0x2f, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, - 0x6c, 0x69, 0x76, 0x65, 0x6b, 0x69, 0x74, 0x2f, 0x6c, 0x69, 0x76, 0x65, 0x6b, 0x69, 0x74, 0x2d, - 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2f, 0x6c, 0x69, 0x76, - 0x65, 0x6b, 0x69, 0x74, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, + 0x74, 0x6f, 0x22, 0x77, 0x0a, 0x11, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x52, 0x6f, 0x6f, 0x6d, + 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, + 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x23, 0x0a, 0x0d, 0x65, + 0x6d, 0x70, 0x74, 0x79, 0x5f, 0x74, 0x69, 0x6d, 0x65, 0x6f, 0x75, 0x74, 0x18, 0x02, 0x20, 0x01, + 0x28, 0x0d, 0x52, 0x0c, 0x65, 0x6d, 0x70, 0x74, 0x79, 0x54, 0x69, 0x6d, 0x65, 0x6f, 0x75, 0x74, + 0x12, 0x29, 0x0a, 0x10, 0x6d, 0x61, 0x78, 0x5f, 0x70, 0x61, 0x72, 0x74, 0x69, 0x63, 0x69, 0x70, + 0x61, 0x6e, 0x74, 0x73, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x0f, 0x6d, 0x61, 0x78, 0x50, + 0x61, 0x72, 0x74, 0x69, 0x63, 0x69, 0x70, 0x61, 0x6e, 0x74, 0x73, 0x22, 0x24, 0x0a, 0x0e, 0x47, + 0x65, 0x74, 0x52, 0x6f, 0x6f, 0x6d, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x12, 0x0a, + 0x04, 0x72, 0x6f, 0x6f, 0x6d, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x72, 0x6f, 0x6f, + 0x6d, 0x22, 0x27, 0x0a, 0x11, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x52, 0x6f, 0x6f, 0x6d, 0x52, + 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x12, 0x0a, 0x04, 0x72, 0x6f, 0x6f, 0x6d, 0x18, 0x01, + 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x72, 0x6f, 0x6f, 0x6d, 0x22, 0x14, 0x0a, 0x12, 0x44, 0x65, + 0x6c, 0x65, 0x74, 0x65, 0x52, 0x6f, 0x6f, 0x6d, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, + 0x32, 0xc8, 0x01, 0x0a, 0x0b, 0x52, 0x6f, 0x6f, 0x6d, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, + 0x12, 0x3b, 0x0a, 0x0a, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x52, 0x6f, 0x6f, 0x6d, 0x12, 0x1a, + 0x2e, 0x6c, 0x69, 0x76, 0x65, 0x6b, 0x69, 0x74, 0x2e, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x52, + 0x6f, 0x6f, 0x6d, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x11, 0x2e, 0x6c, 0x69, 0x76, + 0x65, 0x6b, 0x69, 0x74, 0x2e, 0x52, 0x6f, 0x6f, 0x6d, 0x49, 0x6e, 0x66, 0x6f, 0x12, 0x35, 0x0a, + 0x07, 0x47, 0x65, 0x74, 0x52, 0x6f, 0x6f, 0x6d, 0x12, 0x17, 0x2e, 0x6c, 0x69, 0x76, 0x65, 0x6b, + 0x69, 0x74, 0x2e, 0x47, 0x65, 0x74, 0x52, 0x6f, 0x6f, 0x6d, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, + 0x74, 0x1a, 0x11, 0x2e, 0x6c, 0x69, 0x76, 0x65, 0x6b, 0x69, 0x74, 0x2e, 0x52, 0x6f, 0x6f, 0x6d, + 0x49, 0x6e, 0x66, 0x6f, 0x12, 0x45, 0x0a, 0x0a, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x52, 0x6f, + 0x6f, 0x6d, 0x12, 0x1a, 0x2e, 0x6c, 0x69, 0x76, 0x65, 0x6b, 0x69, 0x74, 0x2e, 0x44, 0x65, 0x6c, + 0x65, 0x74, 0x65, 0x52, 0x6f, 0x6f, 0x6d, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1b, + 0x2e, 0x6c, 0x69, 0x76, 0x65, 0x6b, 0x69, 0x74, 0x2e, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x52, + 0x6f, 0x6f, 0x6d, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x42, 0x31, 0x5a, 0x2f, 0x67, + 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x6c, 0x69, 0x76, 0x65, 0x6b, 0x69, + 0x74, 0x2f, 0x6c, 0x69, 0x76, 0x65, 0x6b, 0x69, 0x74, 0x2d, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, + 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2f, 0x6c, 0x69, 0x76, 0x65, 0x6b, 0x69, 0x74, 0x62, 0x06, + 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, } var ( diff --git a/proto/livekit/room.twirp.go b/proto/livekit/room.twirp.go index 085f52f4f..b57fa66da 100644 --- a/proto/livekit/room.twirp.go +++ b/proto/livekit/room.twirp.go @@ -1595,23 +1595,23 @@ func callClientError(ctx context.Context, h *twirp.ClientHooks, err twirp.Error) } var twirpFileDescriptor0 = []byte{ - // 283 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x74, 0x91, 0x4f, 0x4f, 0x83, 0x40, - 0x10, 0xc5, 0x53, 0x0f, 0x25, 0x4e, 0xad, 0xca, 0xc6, 0xa4, 0x0d, 0x5e, 0x0c, 0x5e, 0x6c, 0xa2, - 0x10, 0x35, 0x9e, 0xbc, 0xf9, 0x27, 0xa6, 0x37, 0x83, 0x9e, 0xbc, 0x10, 0x0a, 0xa3, 0x6e, 0x64, - 0x19, 0x5c, 0x06, 0x52, 0xbf, 0xa1, 0x1f, 0xcb, 0xb0, 0xd0, 0x96, 0xa6, 0xf5, 0x44, 0xe6, 0xf7, - 0x1e, 0x3b, 0xef, 0xed, 0x02, 0x68, 0x22, 0xe5, 0xe5, 0x9a, 0x98, 0x84, 0x95, 0xca, 0x0a, 0xbf, - 0x24, 0x3b, 0x03, 0x45, 0x09, 0xa6, 0x0d, 0x75, 0x63, 0xb0, 0xef, 0x35, 0x46, 0x8c, 0x01, 0x91, - 0x0a, 0xf0, 0xbb, 0xc4, 0x82, 0xc5, 0x29, 0x0c, 0x51, 0xe5, 0xfc, 0x13, 0xb2, 0x54, 0x48, 0x25, - 0x8f, 0x7b, 0x27, 0xbd, 0xb3, 0x61, 0xb0, 0x67, 0xe0, 0x6b, 0xc3, 0xc4, 0x04, 0x0e, 0x55, 0x34, - 0x0f, 0xf3, 0x48, 0xb3, 0x8c, 0x65, 0x1e, 0x65, 0x5c, 0x8c, 0x77, 0x8c, 0xef, 0x40, 0x45, 0xf3, - 0xe7, 0x0e, 0x76, 0x27, 0xb0, 0xff, 0x84, 0xdc, 0xdd, 0x30, 0x02, 0xab, 0x8e, 0x16, 0xca, 0xc4, - 0x9c, 0xbd, 0x1b, 0xf4, 0xeb, 0x71, 0x9a, 0xb8, 0xe7, 0x60, 0x3f, 0x60, 0x8a, 0xeb, 0x79, 0xfe, - 0x75, 0x1f, 0x81, 0xe8, 0xba, 0x8b, 0x9c, 0xb2, 0x02, 0xaf, 0x7e, 0x7b, 0x30, 0xa8, 0xc1, 0x0b, - 0xea, 0x4a, 0xc6, 0x28, 0x6e, 0x01, 0x56, 0x1d, 0x85, 0xe3, 0xb5, 0x17, 0xe1, 0x6d, 0x14, 0x77, - 0xec, 0xa5, 0x56, 0xd3, 0x69, 0xf6, 0x4e, 0xe2, 0x06, 0xac, 0x36, 0xbb, 0x18, 0x2d, 0xd5, 0xf5, - 0x36, 0xdb, 0x7e, 0x7b, 0x04, 0x58, 0x25, 0xeb, 0xec, 0xdc, 0x28, 0xe7, 0x1c, 0x6f, 0xd5, 0x9a, - 0x2a, 0x77, 0x97, 0x6f, 0xfe, 0x87, 0xe4, 0xcf, 0x72, 0xe6, 0xc5, 0xa4, 0xfc, 0xd6, 0xb8, 0xf8, - 0x5e, 0x14, 0xa8, 0x2b, 0xd4, 0xbe, 0x79, 0xc9, 0x05, 0x9c, 0xf5, 0xcd, 0x78, 0xfd, 0x17, 0x00, - 0x00, 0xff, 0xff, 0xb4, 0xf1, 0xcd, 0x1a, 0xfc, 0x01, 0x00, 0x00, + // 288 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x6c, 0x91, 0x4f, 0x4b, 0xc3, 0x40, + 0x10, 0xc5, 0x89, 0x8a, 0xc5, 0xa9, 0x55, 0xbb, 0x08, 0x86, 0x78, 0x29, 0x51, 0xb0, 0x1e, 0x4c, + 0x50, 0xf1, 0xe4, 0xcd, 0x3f, 0x88, 0x37, 0x89, 0x9e, 0xbc, 0x94, 0x6d, 0x1c, 0x75, 0x31, 0x9b, + 0x89, 0x9b, 0x49, 0xac, 0xdf, 0xd0, 0x8f, 0x25, 0xf9, 0xd7, 0x46, 0xd3, 0xd3, 0xce, 0xfe, 0xe6, + 0x2d, 0xf3, 0xde, 0x2c, 0x80, 0x21, 0xd2, 0x5e, 0x62, 0x88, 0x49, 0xf4, 0x22, 0x95, 0xe3, 0x87, + 0x62, 0xa7, 0xaf, 0xe9, 0x05, 0xa3, 0x8a, 0xba, 0x5f, 0x30, 0xbc, 0x36, 0x28, 0x19, 0x03, 0x22, + 0x1d, 0xe0, 0x67, 0x86, 0x29, 0x0b, 0x01, 0x6b, 0xb1, 0xd4, 0x68, 0x5b, 0x23, 0x6b, 0xbc, 0x11, + 0x94, 0xb5, 0x38, 0x80, 0x01, 0xea, 0x84, 0xbf, 0x27, 0xac, 0x34, 0x52, 0xc6, 0xf6, 0xca, 0xc8, + 0x1a, 0x0f, 0x82, 0xcd, 0x12, 0x3e, 0x55, 0x4c, 0x1c, 0xc3, 0x8e, 0x96, 0xb3, 0x49, 0x22, 0x0d, + 0xab, 0x50, 0x25, 0x32, 0xe6, 0xd4, 0x5e, 0x2d, 0x75, 0xdb, 0x5a, 0xce, 0x1e, 0x5a, 0xd8, 0x3d, + 0x84, 0xad, 0x3b, 0xe4, 0x7f, 0x53, 0x0b, 0xbb, 0xcd, 0xd4, 0xa2, 0x76, 0x8f, 0x60, 0x78, 0x83, + 0x11, 0x76, 0xec, 0x75, 0x84, 0xbb, 0x20, 0xda, 0xc2, 0x34, 0xa1, 0x38, 0xc5, 0xb3, 0x1f, 0x0b, + 0xfa, 0x05, 0x78, 0x44, 0x93, 0xab, 0x10, 0xc5, 0x25, 0xc0, 0x22, 0xad, 0x70, 0xbc, 0x7a, 0x25, + 0x5e, 0x67, 0x05, 0xce, 0x70, 0xde, 0x2b, 0xe8, 0x7d, 0xfc, 0x4a, 0xe2, 0x02, 0x7a, 0xb5, 0x63, + 0xb1, 0x37, 0xef, 0xfe, 0xcd, 0xb0, 0xec, 0xd9, 0x2d, 0xc0, 0xc2, 0x59, 0x6b, 0x66, 0x27, 0x97, + 0xb3, 0xbf, 0xb4, 0x57, 0x45, 0xb9, 0x3a, 0x7d, 0xf6, 0xdf, 0x14, 0xbf, 0x67, 0x53, 0x2f, 0x24, + 0xed, 0xd7, 0xc2, 0xe6, 0x3c, 0x49, 0xd1, 0xe4, 0x68, 0xfc, 0xf2, 0x4f, 0x1b, 0x38, 0x5d, 0x2f, + 0xaf, 0xe7, 0xbf, 0x01, 0x00, 0x00, 0xff, 0xff, 0x9f, 0xf2, 0xc7, 0x37, 0x06, 0x02, 0x00, 0x00, } diff --git a/proto/model.proto b/proto/model.proto index eb680a207..452246933 100644 --- a/proto/model.proto +++ b/proto/model.proto @@ -18,22 +18,22 @@ message NodeStats { // internal type, for serialization with proto message Room { string sid = 1; - uint32 empty_timeout = 2; - uint32 max_participants = 3; - int64 creation_time = 4; - string token = 5; + string name = 2; + uint32 empty_timeout = 3; + uint32 max_participants = 4; + int64 creation_time = 5; } message RoomInfo { string sid = 1; - string node_ip = 2; - int64 creation_time = 3; - string token = 4; + string name = 2; + string node_ip = 3; + int64 creation_time = 4; } message ParticipantInfo { enum State { - // websocket connected, but not offered yet + // websocket' connected, but not offered yet JOINING = 0; // server received client offer JOINED = 1; diff --git a/proto/room.proto b/proto/room.proto index d20513cbc..3475fa51f 100644 --- a/proto/room.proto +++ b/proto/room.proto @@ -16,17 +16,18 @@ service RoomService { } message CreateRoomRequest { + string name = 1; // number of seconds the room should cleanup after being empty - uint32 empty_timeout = 1; - uint32 max_participants = 2; + uint32 empty_timeout = 2; + uint32 max_participants = 3; } message GetRoomRequest { - string room_id = 1; + string room = 1; } message DeleteRoomRequest { - string room_id = 1; + string room = 1; } message DeleteRoomResponse {