Commit 2890d21c authored by Juliusz Chroboczek's avatar Juliusz Chroboczek

Add group permissions.

parent cb1782b6
...@@ -89,6 +89,7 @@ type clientMessage struct { ...@@ -89,6 +89,7 @@ type clientMessage struct {
Id string `json:"id,omitempty"` Id string `json:"id,omitempty"`
Username string `json:"username,omitempty"` Username string `json:"username,omitempty"`
Password string `json:"password,omitempty"` Password string `json:"password,omitempty"`
Permissions userPermission `json:"permissions,omitempty"`
Group string `json:"group,omitempty"` Group string `json:"group,omitempty"`
Value string `json:"value,omitempty"` Value string `json:"value,omitempty"`
Message string `json:"message,omitempty"` Message string `json:"message,omitempty"`
...@@ -149,7 +150,7 @@ func startClient(conn *websocket.Conn) (err error) { ...@@ -149,7 +150,7 @@ func startClient(conn *websocket.Conn) (err error) {
c.writerDone = make(chan struct{}) c.writerDone = make(chan struct{})
go clientWriter(conn, c.writeCh, c.writerDone) go clientWriter(conn, c.writeCh, c.writerDone)
g, users, err := addClient(m.Group, c) g, users, err := addClient(m.Group, c, m.Username, m.Password)
if err != nil { if err != nil {
return return
} }
...@@ -262,7 +263,7 @@ func addUpConn(c *client, id string) (*upConnection, error) { ...@@ -262,7 +263,7 @@ func addUpConn(c *client, id string) (*upConnection, error) {
clients := c.group.getClients(c) clients := c.group.getClients(c)
for _, cc := range clients { for _, cc := range clients {
cc.action(addTrackAction{id, local, u, done}) cc.action(addTrackAction{id, local, u, done})
if(done && u.label != "") { if done && u.label != "" {
cc.action(addLabelAction{id, u.label}) cc.action(addLabelAction{id, u.label})
} }
} }
...@@ -389,7 +390,7 @@ func delDownConn(c *client, id string) { ...@@ -389,7 +390,7 @@ func delDownConn(c *client, id string) {
log.Printf("Deleting unknown connection") log.Printf("Deleting unknown connection")
return return
} }
conn := c.down[id]; conn := c.down[id]
if conn == nil { if conn == nil {
log.Printf("Deleting unknown connection") log.Printf("Deleting unknown connection")
return return
...@@ -667,6 +668,11 @@ func clientLoop(c *client, conn *websocket.Conn) error { ...@@ -667,6 +668,11 @@ func clientLoop(c *client, conn *websocket.Conn) error {
g := c.group g := c.group
c.write(clientMessage{
Type: "permissions",
Permissions: c.permissions,
})
for _, cc := range g.getClients(c) { for _, cc := range g.getClients(c) {
cc.action(pushTracksAction{c}) cc.action(pushTracksAction{c})
} }
...@@ -721,7 +727,7 @@ func clientLoop(c *client, conn *websocket.Conn) error { ...@@ -721,7 +727,7 @@ func clientLoop(c *client, conn *websocket.Conn) error {
for _, u := range c.up { for _, u := range c.up {
var done bool var done bool
for i, p := range u.pairs { for i, p := range u.pairs {
done = i >= u.streamCount - 1 done = i >= u.streamCount-1
a.c.action(addTrackAction{ a.c.action(addTrackAction{
u.id, p.local, u, u.id, p.local, u,
done, done,
...@@ -747,6 +753,9 @@ func clientLoop(c *client, conn *websocket.Conn) error { ...@@ -747,6 +753,9 @@ func clientLoop(c *client, conn *websocket.Conn) error {
func handleClientMessage(c *client, m clientMessage) error { func handleClientMessage(c *client, m clientMessage) error {
switch m.Type { switch m.Type {
case "offer": case "offer":
if !c.permissions.Present {
return userError("not authorized")
}
if m.Offer == nil { if m.Offer == nil {
return protocolError("null offer") return protocolError("null offer")
} }
......
...@@ -6,7 +6,10 @@ ...@@ -6,7 +6,10 @@
package main package main
import ( import (
"encoding/json"
"log" "log"
"os"
"path/filepath"
"sync" "sync"
"github.com/pion/webrtc/v2" "github.com/pion/webrtc/v2"
...@@ -37,6 +40,7 @@ type client struct { ...@@ -37,6 +40,7 @@ type client struct {
group *group group *group
id string id string
username string username string
permissions userPermission
done chan struct{} done chan struct{}
writeCh chan interface{} writeCh chan interface{}
writerDone chan struct{} writerDone chan struct{}
...@@ -47,7 +51,7 @@ type client struct { ...@@ -47,7 +51,7 @@ type client struct {
type group struct { type group struct {
name string name string
public bool description *groupDescription
mu sync.Mutex mu sync.Mutex
clients []*client clients []*client
...@@ -102,8 +106,13 @@ func addGroup(name string) (*group, error) { ...@@ -102,8 +106,13 @@ func addGroup(name string) (*group, error) {
g := groups.groups[name] g := groups.groups[name]
if g == nil { if g == nil {
desc, err := getDescription(name)
if err != nil {
return nil, err
}
g = &group{ g = &group{
name: name, name: name,
description: desc,
} }
groups.groups[name] = g groups.groups[name] = g
} }
...@@ -130,12 +139,18 @@ type userid struct { ...@@ -130,12 +139,18 @@ type userid struct {
username string username string
} }
func addClient(name string, client *client) (*group, []userid, error) { func addClient(name string, client *client, user, pass string) (*group, []userid, error) {
g, err := addGroup(name) g, err := addGroup(name)
if err != nil { if err != nil {
return nil, nil, err return nil, nil, err
} }
perms, err := getPermission(g.description, user, pass)
if err != nil {
return nil, nil, err
}
client.permissions = perms
var users []userid var users []userid
g.mu.Lock() g.mu.Lock()
defer g.mu.Unlock() defer g.mu.Unlock()
...@@ -182,8 +197,8 @@ func (g *group) Range(f func(c *client) bool) { ...@@ -182,8 +197,8 @@ func (g *group) Range(f func(c *client) bool) {
defer g.mu.Unlock() defer g.mu.Unlock()
for _, c := range g.clients { for _, c := range g.clients {
ok := f(c) ok := f(c)
if(!ok){ if !ok {
break; break
} }
} }
} }
...@@ -218,6 +233,83 @@ func (c *client) action(m interface{}) error { ...@@ -218,6 +233,83 @@ func (c *client) action(m interface{}) error {
} }
} }
type groupUser struct {
Username string `json:"username,omitempty"`
Password string `json:"password,omitempty"`
}
func matchUser(user, pass string, users []groupUser) (bool, bool) {
for _, u := range users {
if (u.Username == "" || u.Username == user) {
return true, (u.Password == "" || u.Password == pass)
}
}
return false, false
}
type groupDescription struct {
Public bool `json:"public,omitempty"`
AllowAnonymous bool `json:"allow-anonymous,omitempty"`
Admin []groupUser `json:"admin,omitempty"`
Presenter []groupUser `json:"presenter,omitempty"`
Other []groupUser `json:"other,omitempty"`
}
func getDescription(name string) (*groupDescription, error) {
r, err := os.Open(filepath.Join(groupsDir, name+".json"))
if err != nil {
if os.IsNotExist(err) {
err = userError("group does not exist")
} else if os.IsPermission(err) {
err = userError("unauthorised")
}
return nil, err
}
defer r.Close()
var desc groupDescription
d := json.NewDecoder(r)
err = d.Decode(&desc)
if err != nil {
return nil, err
}
return &desc, nil
}
type userPermission struct {
Admin bool `json:"admin,omitempty"`
Present bool `json:"present,omitempty"`
}
func getPermission(desc *groupDescription, user, pass string) (userPermission, error) {
var p userPermission
if !desc.AllowAnonymous && user == "" {
return p, userError("anonymous users not allowed in this group")
}
if found, good := matchUser(user, pass, desc.Admin); found {
if good {
p.Admin = true
p.Present = true
return p, nil
}
return p, userError("not authorized")
}
if found, good := matchUser(user, pass, desc.Presenter); found {
if good {
p.Present = true
return p, nil
}
return p, userError("not authorized")
}
if found, good := matchUser(user, pass, desc.Other); found {
if good {
return p, nil
}
return p, userError("not authorized")
}
return p, userError("not authorized")
}
type publicGroup struct { type publicGroup struct {
Name string `json:"name"` Name string `json:"name"`
ClientCount int `json:"clientCount"` ClientCount int `json:"clientCount"`
...@@ -228,7 +320,7 @@ func getPublicGroups() []publicGroup { ...@@ -228,7 +320,7 @@ func getPublicGroups() []publicGroup {
groups.mu.Lock() groups.mu.Lock()
defer groups.mu.Unlock() defer groups.mu.Unlock()
for _, g := range groups.groups { for _, g := range groups.groups {
if g.public { if g.description.Public {
gs = append(gs, publicGroup{ gs = append(gs, publicGroup{
Name: g.name, Name: g.name,
ClientCount: len(g.clients), ClientCount: len(g.clients),
......
...@@ -22,6 +22,7 @@ import ( ...@@ -22,6 +22,7 @@ import (
var httpAddr string var httpAddr string
var staticRoot string var staticRoot string
var dataDir string var dataDir string
var groupsDir string
var iceFilename string var iceFilename string
func main() { func main() {
...@@ -30,6 +31,8 @@ func main() { ...@@ -30,6 +31,8 @@ func main() {
"web server root `directory`") "web server root `directory`")
flag.StringVar(&dataDir, "data", "./data/", flag.StringVar(&dataDir, "data", "./data/",
"data `directory`") "data `directory`")
flag.StringVar(&groupsDir, "groups", "./groups/",
"group description `directory`")
flag.Parse() flag.Parse()
iceFilename = filepath.Join(staticRoot, "ice-servers.json") iceFilename = filepath.Join(staticRoot, "ice-servers.json")
......
...@@ -29,9 +29,9 @@ ...@@ -29,9 +29,9 @@
<div id="optionsdiv"> <div id="optionsdiv">
<label for="presenterbox">Present:</label> <label for="presenterbox">Present:</label>
<input id="presenterbox" type="checkbox"/> <input id="presenterbox" type="checkbox"/ disabled>
<label for="sharebox">Share screen:</label> <label for="sharebox">Share screen:</label>
<input id="sharebox" type="checkbox"/> <input id="sharebox" type="checkbox"/ disabled>
</div> </div>
</div> </div>
......
...@@ -279,8 +279,10 @@ function serverConnect() { ...@@ -279,8 +279,10 @@ function serverConnect() {
socket.onclose = function(e) { socket.onclose = function(e) {
setConnected(false); setConnected(false);
document.getElementById('presenterbox').checked = false; document.getElementById('presenterbox').checked = false;
document.getElementById('presenterbox').disabled = true;
setLocalMedia(); setLocalMedia();
document.getElementById('sharebox').checked = false; document.getElementById('sharebox').checked = false;
document.getElementById('sharebox').disabled = true;
setShareMedia(); setShareMedia();
reject(new Error('websocket close ' + e.code + ' ' + e.reason)); reject(new Error('websocket close ' + e.code + ' ' + e.reason));
}; };
...@@ -305,6 +307,9 @@ function serverConnect() { ...@@ -305,6 +307,9 @@ function serverConnect() {
case 'label': case 'label':
gotLabel(m.id, m.value); gotLabel(m.id, m.value);
break; break;
case 'permissions':
gotPermissions(m.permissions);
break;
case 'user': case 'user':
gotUser(m.id, m.username, m.del); gotUser(m.id, m.username, m.del);
break; break;
...@@ -483,6 +488,11 @@ function gotUser(id, name, del) { ...@@ -483,6 +488,11 @@ function gotUser(id, name, del) {
addUser(id, name); addUser(id, name);
} }
function gotPermissions(permissions) {
document.getElementById('presenterbox').disabled = !permissions.present;
document.getElementById('sharebox').disabled = !permissions.present;
}
const urlRegexp = /https?:\/\/[-a-zA-Z0-9@:%/._\+~#=?]+[-a-zA-Z0-9@:%/_\+~#=]/g; const urlRegexp = /https?:\/\/[-a-zA-Z0-9@:%/._\+~#=?]+[-a-zA-Z0-9@:%/_\+~#=]/g;
function formatLine(line) { function formatLine(line) {
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment