mirror of
https://github.com/jech/galene.git
synced 2024-11-22 16:45:58 +01:00
Replace ClientPermissions with a list of strings.
Now that we support external auth, the permissions list is open-ended. Make it a list for simplicity.
This commit is contained in:
parent
439dbabaa5
commit
a86fb08f6c
11 changed files with 213 additions and 175 deletions
|
@ -385,7 +385,7 @@ allowed to join, then the authorisation server replies with a signed JWT
|
||||||
{
|
{
|
||||||
"sub": username,
|
"sub": username,
|
||||||
"aud": "https://galene.example.org/group/groupname",
|
"aud": "https://galene.example.org/group/groupname",
|
||||||
"permissions": ["present": true],
|
"permissions": ["present"],
|
||||||
"iat": now,
|
"iat": now,
|
||||||
"exp": now + 30s,
|
"exp": now + 30s,
|
||||||
"iss": authorisation server URL
|
"iss": authorisation server URL
|
||||||
|
|
|
@ -59,21 +59,19 @@ func (client *Client) Username() string {
|
||||||
return "RECORDING"
|
return "RECORDING"
|
||||||
}
|
}
|
||||||
|
|
||||||
func (client *Client) SetPermissions(perms group.ClientPermissions) {
|
func (client *Client) SetPermissions(perms []string) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
func (client *Client) Permissions() group.ClientPermissions {
|
func (client *Client) Permissions() []string {
|
||||||
return group.ClientPermissions{
|
return []string{"system"}
|
||||||
System: true,
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (client *Client) Data() map[string]interface{} {
|
func (client *Client) Data() map[string]interface{} {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (client *Client) PushClient(group, kind, id, username string, permissions group.ClientPermissions, data map[string]interface{}) error {
|
func (client *Client) PushClient(group, kind, id, username string, perms []string, data map[string]interface{}) error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -81,13 +81,6 @@ type ClientPattern struct {
|
||||||
Password *Password `json:"password,omitempty"`
|
Password *Password `json:"password,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type ClientPermissions struct {
|
|
||||||
Op bool `json:"op,omitempty"`
|
|
||||||
Present bool `json:"present,omitempty"`
|
|
||||||
Record bool `json:"record,omitempty"`
|
|
||||||
System bool `json:"system,omitempty"`
|
|
||||||
}
|
|
||||||
|
|
||||||
type ClientCredentials struct {
|
type ClientCredentials struct {
|
||||||
System bool
|
System bool
|
||||||
Username string
|
Username string
|
||||||
|
@ -99,12 +92,12 @@ type Client interface {
|
||||||
Group() *Group
|
Group() *Group
|
||||||
Id() string
|
Id() string
|
||||||
Username() string
|
Username() string
|
||||||
Permissions() ClientPermissions
|
Permissions() []string
|
||||||
SetPermissions(ClientPermissions)
|
SetPermissions([]string)
|
||||||
Data() map[string]interface{}
|
Data() map[string]interface{}
|
||||||
PushConn(g *Group, id string, conn conn.Up, tracks []conn.UpTrack, replace string) error
|
PushConn(g *Group, id string, conn conn.Up, tracks []conn.UpTrack, replace string) error
|
||||||
RequestConns(target Client, g *Group, id string) error
|
RequestConns(target Client, g *Group, id string) error
|
||||||
Joined(group, kind string) error
|
Joined(group, kind string) error
|
||||||
PushClient(group, kind, id, username string, permissions ClientPermissions, data map[string]interface{}) error
|
PushClient(group, kind, id, username string, perms []string, data map[string]interface{}) error
|
||||||
Kick(id, user, message string) error
|
Kick(id, user, message string) error
|
||||||
}
|
}
|
||||||
|
|
135
group/group.go
135
group/group.go
|
@ -544,6 +544,15 @@ func deleteUnlocked(g *Group) bool {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func member(v string, l []string) bool {
|
||||||
|
for _, w := range l {
|
||||||
|
if v == w {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
func AddClient(group string, c Client, creds ClientCredentials) (*Group, error) {
|
func AddClient(group string, c Client, creds ClientCredentials) (*Group, error) {
|
||||||
g, err := Add(group, nil)
|
g, err := Add(group, nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -555,7 +564,7 @@ func AddClient(group string, c Client, creds ClientCredentials) (*Group, error)
|
||||||
|
|
||||||
clients := g.getClientsUnlocked(nil)
|
clients := g.getClientsUnlocked(nil)
|
||||||
|
|
||||||
if !c.Permissions().System {
|
if !member("system", c.Permissions()) {
|
||||||
perms, err := g.description.GetPermission(group, creds)
|
perms, err := g.description.GetPermission(group, creds)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
|
@ -563,7 +572,7 @@ func AddClient(group string, c Client, creds ClientCredentials) (*Group, error)
|
||||||
|
|
||||||
c.SetPermissions(perms)
|
c.SetPermissions(perms)
|
||||||
|
|
||||||
if !perms.Op {
|
if !member("op", perms) {
|
||||||
if g.locked != nil {
|
if g.locked != nil {
|
||||||
m := *g.locked
|
m := *g.locked
|
||||||
if m == "" {
|
if m == "" {
|
||||||
|
@ -574,7 +583,7 @@ func AddClient(group string, c Client, creds ClientCredentials) (*Group, error)
|
||||||
if g.description.Autokick {
|
if g.description.Autokick {
|
||||||
ops := false
|
ops := false
|
||||||
for _, c := range clients {
|
for _, c := range clients {
|
||||||
if c.Permissions().Op {
|
if member("op", c.Permissions()) {
|
||||||
ops = true
|
ops = true
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
|
@ -588,7 +597,7 @@ func AddClient(group string, c Client, creds ClientCredentials) (*Group, error)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if !perms.Op && g.description.MaxClients > 0 {
|
if !member("op", perms) && g.description.MaxClients > 0 {
|
||||||
if len(g.clients) >= g.description.MaxClients {
|
if len(g.clients) >= g.description.MaxClients {
|
||||||
return nil, UserError("too many users")
|
return nil, UserError("too many users")
|
||||||
}
|
}
|
||||||
|
@ -627,7 +636,7 @@ func autoLockKick(g *Group, clients []Client) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
for _, c := range clients {
|
for _, c := range clients {
|
||||||
if c.Permissions().Op {
|
if member("op", c.Permissions()) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -665,7 +674,7 @@ func DelClient(c Client) {
|
||||||
c.Joined(g.Name(), "leave")
|
c.Joined(g.Name(), "leave")
|
||||||
for _, cc := range clients {
|
for _, cc := range clients {
|
||||||
cc.PushClient(
|
cc.PushClient(
|
||||||
g.Name(), "delete", c.Id(), "", ClientPermissions{}, nil,
|
g.Name(), "delete", c.Id(), "", nil, nil,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
autoLockKick(g, clients)
|
autoLockKick(g, clients)
|
||||||
|
@ -1066,82 +1075,76 @@ func GetDescription(name string) (*Description, error) {
|
||||||
return &desc, nil
|
return &desc, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (desc *Description) GetPermission(group string, creds ClientCredentials) (ClientPermissions, error) {
|
func (desc *Description) GetPermission(group string, creds ClientCredentials) ([]string, error) {
|
||||||
var p ClientPermissions
|
|
||||||
if !desc.AllowAnonymous && creds.Username == "" {
|
if !desc.AllowAnonymous && creds.Username == "" {
|
||||||
return p, ErrAnonymousNotAuthorised
|
return nil, ErrAnonymousNotAuthorised
|
||||||
}
|
}
|
||||||
|
|
||||||
if found, good := matchClient(group, creds, desc.Op); found {
|
if creds.Token == "" {
|
||||||
if good {
|
if found, good := matchClient(group, creds, desc.Op); found {
|
||||||
p.Op = true
|
if good {
|
||||||
p.Present = true
|
var p []string
|
||||||
if desc.AllowRecording {
|
p = []string{"op", "present"}
|
||||||
p.Record = true
|
if desc.AllowRecording {
|
||||||
|
p = append(p, "record")
|
||||||
|
}
|
||||||
|
return p, nil
|
||||||
}
|
}
|
||||||
return p, nil
|
return nil, ErrNotAuthorised
|
||||||
}
|
}
|
||||||
return p, ErrNotAuthorised
|
if found, good := matchClient(group, creds, desc.Presenter); found {
|
||||||
}
|
if good {
|
||||||
if found, good := matchClient(group, creds, desc.Presenter); found {
|
return []string{"present"}, nil
|
||||||
if good {
|
}
|
||||||
p.Present = true
|
return nil, ErrNotAuthorised
|
||||||
return p, nil
|
|
||||||
}
|
}
|
||||||
return p, ErrNotAuthorised
|
if found, good := matchClient(group, creds, desc.Other); found {
|
||||||
}
|
if good {
|
||||||
if found, good := matchClient(group, creds, desc.Other); found {
|
return nil, nil
|
||||||
if good {
|
}
|
||||||
return p, nil
|
return nil, ErrNotAuthorised
|
||||||
}
|
}
|
||||||
return p, ErrNotAuthorised
|
return nil, ErrNotAuthorised
|
||||||
}
|
}
|
||||||
|
|
||||||
if creds.Token != "" {
|
aud, perms, err := token.Valid(
|
||||||
aud, perms, err := token.Valid(
|
creds.Username, creds.Token, desc.AuthKeys,
|
||||||
creds.Username, creds.Token, desc.AuthKeys,
|
)
|
||||||
)
|
if err != nil {
|
||||||
|
log.Printf("Token authentication: %v", err)
|
||||||
|
return nil, ErrNotAuthorised
|
||||||
|
}
|
||||||
|
conf, err := GetConfiguration()
|
||||||
|
if err != nil {
|
||||||
|
log.Printf("Read config.json: %v", err)
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
ok := false
|
||||||
|
for _, u := range aud {
|
||||||
|
url, err := url.Parse(u)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Printf("Token authentication: %v", err)
|
log.Printf("Token URL: %v", err)
|
||||||
return p, ErrNotAuthorised
|
continue
|
||||||
}
|
}
|
||||||
conf, err := GetConfiguration()
|
// if canonicalHost is not set, we allow tokens
|
||||||
if err != nil {
|
// for any domain name. Hopefully different
|
||||||
log.Printf("Read config.json: %v", err)
|
// servers use distinct keys.
|
||||||
return p, err
|
if conf.CanonicalHost != "" {
|
||||||
}
|
if !strings.EqualFold(
|
||||||
ok := false
|
url.Host, conf.CanonicalHost,
|
||||||
for _, u := range aud {
|
) {
|
||||||
url, err := url.Parse(u)
|
|
||||||
if err != nil {
|
|
||||||
log.Printf("Token URL: %v", err)
|
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
// if canonicalHost is not set, we allow tokens
|
|
||||||
// for any domain name. Hopefully different
|
|
||||||
// servers use distinct keys.
|
|
||||||
if conf.CanonicalHost != "" {
|
|
||||||
if !strings.EqualFold(
|
|
||||||
url.Host, conf.CanonicalHost,
|
|
||||||
) {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if url.Path == path.Join("/group", group)+"/" {
|
|
||||||
ok = true
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
if !ok {
|
if url.Path == path.Join("/group", group)+"/" {
|
||||||
return p, ErrNotAuthorised
|
ok = true
|
||||||
|
break
|
||||||
}
|
}
|
||||||
p.Op, _ = perms["op"].(bool)
|
|
||||||
p.Present, _ = perms["present"].(bool)
|
|
||||||
p.Record, _ = perms["record"].(bool)
|
|
||||||
return p, nil
|
|
||||||
}
|
}
|
||||||
|
if !ok {
|
||||||
return p, ErrNotAuthorised
|
return nil, ErrNotAuthorised
|
||||||
|
}
|
||||||
|
return perms, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
type Status struct {
|
type Status struct {
|
||||||
|
|
|
@ -132,29 +132,29 @@ var badClients = []ClientCredentials{
|
||||||
|
|
||||||
type credPerm struct {
|
type credPerm struct {
|
||||||
c ClientCredentials
|
c ClientCredentials
|
||||||
p ClientPermissions
|
p []string
|
||||||
}
|
}
|
||||||
|
|
||||||
var goodClients = []credPerm{
|
var goodClients = []credPerm{
|
||||||
{
|
{
|
||||||
ClientCredentials{Username: "jch", Password: "topsecret"},
|
ClientCredentials{Username: "jch", Password: "topsecret"},
|
||||||
ClientPermissions{Op: true, Present: true},
|
[]string{"op", "present"},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
ClientCredentials{Username: "john", Password: "secret"},
|
ClientCredentials{Username: "john", Password: "secret"},
|
||||||
ClientPermissions{Present: true},
|
[]string{"present"},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
ClientCredentials{Username: "john", Password: "secret2"},
|
ClientCredentials{Username: "john", Password: "secret2"},
|
||||||
ClientPermissions{Present: true},
|
[]string{"present"},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
ClientCredentials{Username: "james", Password: "secret3"},
|
ClientCredentials{Username: "james", Password: "secret3"},
|
||||||
ClientPermissions{},
|
nil,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
ClientCredentials{Username: "paul", Password: "secret3"},
|
ClientCredentials{Username: "paul", Password: "secret3"},
|
||||||
ClientPermissions{},
|
nil,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -56,7 +56,7 @@ type webClient struct {
|
||||||
group *group.Group
|
group *group.Group
|
||||||
id string
|
id string
|
||||||
username string
|
username string
|
||||||
permissions group.ClientPermissions
|
permissions []string
|
||||||
data map[string]interface{}
|
data map[string]interface{}
|
||||||
requested map[string][]string
|
requested map[string][]string
|
||||||
done chan struct{}
|
done chan struct{}
|
||||||
|
@ -86,7 +86,7 @@ func (c *webClient) Username() string {
|
||||||
return c.username
|
return c.username
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *webClient) Permissions() group.ClientPermissions {
|
func (c *webClient) Permissions() []string {
|
||||||
return c.permissions
|
return c.permissions
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -94,13 +94,13 @@ func (c *webClient) Data() map[string]interface{} {
|
||||||
return c.data
|
return c.data
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *webClient) SetPermissions(perms group.ClientPermissions) {
|
func (c *webClient) SetPermissions(perms []string) {
|
||||||
c.permissions = perms
|
c.permissions = perms
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *webClient) PushClient(group, kind, id, username string, permissions group.ClientPermissions, data map[string]interface{}) error {
|
func (c *webClient) PushClient(group, kind, id, username string, perms []string, data map[string]interface{}) error {
|
||||||
return c.action(pushClientAction{
|
return c.action(pushClientAction{
|
||||||
group, kind, id, username, permissions, data,
|
group, kind, id, username, perms, data,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -115,7 +115,7 @@ type clientMessage struct {
|
||||||
Password string `json:"password,omitempty"`
|
Password string `json:"password,omitempty"`
|
||||||
Token string `json:"token,omitempty"`
|
Token string `json:"token,omitempty"`
|
||||||
Privileged bool `json:"privileged,omitempty"`
|
Privileged bool `json:"privileged,omitempty"`
|
||||||
Permissions *group.ClientPermissions `json:"permissions,omitempty"`
|
Permissions []string `json:"permissions,omitempty"`
|
||||||
Status *group.Status `json:"status,omitempty"`
|
Status *group.Status `json:"status,omitempty"`
|
||||||
Data map[string]interface{} `json:"data,omitempty"`
|
Data map[string]interface{} `json:"data,omitempty"`
|
||||||
Group string `json:"group,omitempty"`
|
Group string `json:"group,omitempty"`
|
||||||
|
@ -900,7 +900,7 @@ type pushClientAction struct {
|
||||||
kind string
|
kind string
|
||||||
id string
|
id string
|
||||||
username string
|
username string
|
||||||
permissions group.ClientPermissions
|
permissions []string
|
||||||
data map[string]interface{}
|
data map[string]interface{}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -919,6 +919,33 @@ type kickAction struct {
|
||||||
|
|
||||||
var errEmptyId = group.ProtocolError("empty id")
|
var errEmptyId = group.ProtocolError("empty id")
|
||||||
|
|
||||||
|
func member(v string, l []string) bool {
|
||||||
|
for _, w := range l {
|
||||||
|
if v == w {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
func remove(v string, l []string) []string {
|
||||||
|
for i, w := range l {
|
||||||
|
if v == w {
|
||||||
|
l = append(l[:i], l[i+1:]...)
|
||||||
|
return l
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return l
|
||||||
|
}
|
||||||
|
|
||||||
|
func addnew(v string, l []string) []string {
|
||||||
|
if member(v, l) {
|
||||||
|
return l
|
||||||
|
}
|
||||||
|
l = append(l, v)
|
||||||
|
return l
|
||||||
|
}
|
||||||
|
|
||||||
func clientLoop(c *webClient, ws *websocket.Conn) error {
|
func clientLoop(c *webClient, ws *websocket.Conn) error {
|
||||||
read := make(chan interface{}, 1)
|
read := make(chan interface{}, 1)
|
||||||
go clientReader(ws, read, c.done)
|
go clientReader(ws, read, c.done)
|
||||||
|
@ -1102,12 +1129,13 @@ func handleAction(c *webClient, a interface{}) error {
|
||||||
log.Printf("got client for wrong group")
|
log.Printf("got client for wrong group")
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
perms := append([]string(nil), a.permissions...)
|
||||||
return c.write(clientMessage{
|
return c.write(clientMessage{
|
||||||
Type: "user",
|
Type: "user",
|
||||||
Kind: a.kind,
|
Kind: a.kind,
|
||||||
Id: a.id,
|
Id: a.id,
|
||||||
Username: a.username,
|
Username: a.username,
|
||||||
Permissions: &a.permissions,
|
Permissions: perms,
|
||||||
Data: a.data,
|
Data: a.data,
|
||||||
})
|
})
|
||||||
case joinedAction:
|
case joinedAction:
|
||||||
|
@ -1121,13 +1149,13 @@ func handleAction(c *webClient, a interface{}) error {
|
||||||
data = g.Data()
|
data = g.Data()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
perms := c.permissions
|
perms := append([]string(nil), c.permissions...)
|
||||||
return c.write(clientMessage{
|
return c.write(clientMessage{
|
||||||
Type: "joined",
|
Type: "joined",
|
||||||
Kind: a.kind,
|
Kind: a.kind,
|
||||||
Group: a.group,
|
Group: a.group,
|
||||||
Username: c.username,
|
Username: c.username,
|
||||||
Permissions: &perms,
|
Permissions: perms,
|
||||||
Status: status,
|
Status: status,
|
||||||
Data: data,
|
Data: data,
|
||||||
RTCConfiguration: ice.ICEConfiguration(),
|
RTCConfiguration: ice.ICEConfiguration(),
|
||||||
|
@ -1137,18 +1165,18 @@ func handleAction(c *webClient, a interface{}) error {
|
||||||
if g == nil {
|
if g == nil {
|
||||||
return errors.New("Permissions changed in no group")
|
return errors.New("Permissions changed in no group")
|
||||||
}
|
}
|
||||||
perms := c.permissions
|
perms := append([]string(nil), c.permissions...)
|
||||||
status := g.Status(true)
|
status := g.Status(true)
|
||||||
c.write(clientMessage{
|
c.write(clientMessage{
|
||||||
Type: "joined",
|
Type: "joined",
|
||||||
Kind: "change",
|
Kind: "change",
|
||||||
Group: g.Name(),
|
Group: g.Name(),
|
||||||
Username: c.username,
|
Username: c.username,
|
||||||
Permissions: &perms,
|
Permissions: perms,
|
||||||
Status: &status,
|
Status: &status,
|
||||||
RTCConfiguration: ice.ICEConfiguration(),
|
RTCConfiguration: ice.ICEConfiguration(),
|
||||||
})
|
})
|
||||||
if !c.permissions.Present {
|
if member("present", c.permissions) {
|
||||||
up := getUpConns(c)
|
up := getUpConns(c)
|
||||||
for _, u := range up {
|
for _, u := range up {
|
||||||
err := delUpConn(
|
err := delUpConn(
|
||||||
|
@ -1220,7 +1248,7 @@ func leaveGroup(c *webClient) {
|
||||||
}
|
}
|
||||||
|
|
||||||
group.DelClient(c)
|
group.DelClient(c)
|
||||||
c.permissions = group.ClientPermissions{}
|
c.permissions = nil
|
||||||
c.data = nil
|
c.data = nil
|
||||||
c.requested = make(map[string][]string)
|
c.requested = make(map[string][]string)
|
||||||
c.group = nil
|
c.group = nil
|
||||||
|
@ -1260,17 +1288,17 @@ func setPermissions(g *group.Group, id string, perm string) error {
|
||||||
|
|
||||||
switch perm {
|
switch perm {
|
||||||
case "op":
|
case "op":
|
||||||
c.permissions.Op = true
|
c.permissions = addnew("op", c.permissions)
|
||||||
if g.Description().AllowRecording {
|
if g.Description().AllowRecording {
|
||||||
c.permissions.Record = true
|
c.permissions = addnew("record", c.permissions)
|
||||||
}
|
}
|
||||||
case "unop":
|
case "unop":
|
||||||
c.permissions.Op = false
|
c.permissions = remove("op", c.permissions)
|
||||||
c.permissions.Record = false
|
c.permissions = remove("record", c.permissions)
|
||||||
case "present":
|
case "present":
|
||||||
c.permissions.Present = true
|
c.permissions = addnew("present", c.permissions)
|
||||||
case "unpresent":
|
case "unpresent":
|
||||||
c.permissions.Present = false
|
c.permissions = remove("present", c.permissions)
|
||||||
default:
|
default:
|
||||||
return group.UserError("unknown permission")
|
return group.UserError("unknown permission")
|
||||||
}
|
}
|
||||||
|
@ -1356,7 +1384,6 @@ func handleClientMessage(c *webClient, m clientMessage) error {
|
||||||
Kind: "fail",
|
Kind: "fail",
|
||||||
Group: m.Group,
|
Group: m.Group,
|
||||||
Username: c.username,
|
Username: c.username,
|
||||||
Permissions: &group.ClientPermissions{},
|
|
||||||
Value: s,
|
Value: s,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
@ -1368,7 +1395,6 @@ func handleClientMessage(c *webClient, m clientMessage) error {
|
||||||
Kind: "redirect",
|
Kind: "redirect",
|
||||||
Group: m.Group,
|
Group: m.Group,
|
||||||
Username: c.username,
|
Username: c.username,
|
||||||
Permissions: &group.ClientPermissions{},
|
|
||||||
Value: redirect,
|
Value: redirect,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
@ -1407,7 +1433,7 @@ func handleClientMessage(c *webClient, m clientMessage) error {
|
||||||
if m.Id == "" {
|
if m.Id == "" {
|
||||||
return errEmptyId
|
return errEmptyId
|
||||||
}
|
}
|
||||||
if !c.permissions.Present {
|
if !member("present", c.permissions) {
|
||||||
if m.Replace != "" {
|
if m.Replace != "" {
|
||||||
delUpConn(c, m.Replace, c.id, true)
|
delUpConn(c, m.Replace, c.id, true)
|
||||||
}
|
}
|
||||||
|
@ -1508,7 +1534,7 @@ func handleClientMessage(c *webClient, m clientMessage) error {
|
||||||
Source: m.Source,
|
Source: m.Source,
|
||||||
Dest: m.Dest,
|
Dest: m.Dest,
|
||||||
Username: m.Username,
|
Username: m.Username,
|
||||||
Privileged: c.permissions.Op,
|
Privileged: member("op", c.permissions),
|
||||||
Time: tm,
|
Time: tm,
|
||||||
Kind: m.Kind,
|
Kind: m.Kind,
|
||||||
NoEcho: m.NoEcho,
|
NoEcho: m.NoEcho,
|
||||||
|
@ -1554,7 +1580,7 @@ func handleClientMessage(c *webClient, m clientMessage) error {
|
||||||
log.Printf("broadcast(clearchat): %v", err)
|
log.Printf("broadcast(clearchat): %v", err)
|
||||||
}
|
}
|
||||||
case "lock", "unlock":
|
case "lock", "unlock":
|
||||||
if !c.permissions.Op {
|
if !member("op", c.permissions) {
|
||||||
return c.error(group.UserError("not authorised"))
|
return c.error(group.UserError("not authorised"))
|
||||||
}
|
}
|
||||||
message := ""
|
message := ""
|
||||||
|
@ -1564,7 +1590,7 @@ func handleClientMessage(c *webClient, m clientMessage) error {
|
||||||
}
|
}
|
||||||
g.SetLocked(m.Kind == "lock", message)
|
g.SetLocked(m.Kind == "lock", message)
|
||||||
case "record":
|
case "record":
|
||||||
if !c.permissions.Record {
|
if !member("record", c.permissions) {
|
||||||
return c.error(group.UserError("not authorised"))
|
return c.error(group.UserError("not authorised"))
|
||||||
}
|
}
|
||||||
for _, cc := range g.GetClients(c) {
|
for _, cc := range g.GetClients(c) {
|
||||||
|
@ -1585,7 +1611,7 @@ func handleClientMessage(c *webClient, m clientMessage) error {
|
||||||
}
|
}
|
||||||
requestConns(disk, c.group, "")
|
requestConns(disk, c.group, "")
|
||||||
case "unrecord":
|
case "unrecord":
|
||||||
if !c.permissions.Record {
|
if !member("record", c.permissions) {
|
||||||
return c.error(group.UserError("not authorised"))
|
return c.error(group.UserError("not authorised"))
|
||||||
}
|
}
|
||||||
for _, cc := range g.GetClients(c) {
|
for _, cc := range g.GetClients(c) {
|
||||||
|
@ -1596,7 +1622,7 @@ func handleClientMessage(c *webClient, m clientMessage) error {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
case "subgroups":
|
case "subgroups":
|
||||||
if !c.permissions.Op {
|
if !member("op", c.permissions) {
|
||||||
return c.error(group.UserError("not authorised"))
|
return c.error(group.UserError("not authorised"))
|
||||||
}
|
}
|
||||||
s := ""
|
s := ""
|
||||||
|
@ -1616,7 +1642,7 @@ func handleClientMessage(c *webClient, m clientMessage) error {
|
||||||
Value: s,
|
Value: s,
|
||||||
})
|
})
|
||||||
case "setdata":
|
case "setdata":
|
||||||
if !c.permissions.Op {
|
if !member("op", c.permissions) {
|
||||||
return c.error(group.UserError("not authorised"))
|
return c.error(group.UserError("not authorised"))
|
||||||
}
|
}
|
||||||
data, ok := m.Value.(map[string]interface{})
|
data, ok := m.Value.(map[string]interface{})
|
||||||
|
@ -1636,7 +1662,7 @@ func handleClientMessage(c *webClient, m clientMessage) error {
|
||||||
}
|
}
|
||||||
switch m.Kind {
|
switch m.Kind {
|
||||||
case "op", "unop", "present", "unpresent":
|
case "op", "unop", "present", "unpresent":
|
||||||
if !c.permissions.Op {
|
if !member("op", c.permissions) {
|
||||||
return c.error(group.UserError("not authorised"))
|
return c.error(group.UserError("not authorised"))
|
||||||
}
|
}
|
||||||
err := setPermissions(g, m.Dest, m.Kind)
|
err := setPermissions(g, m.Dest, m.Kind)
|
||||||
|
@ -1644,7 +1670,7 @@ func handleClientMessage(c *webClient, m clientMessage) error {
|
||||||
return c.error(err)
|
return c.error(err)
|
||||||
}
|
}
|
||||||
case "kick":
|
case "kick":
|
||||||
if !c.permissions.Op {
|
if !member("op", c.permissions) {
|
||||||
return c.error(group.UserError("not authorised"))
|
return c.error(group.UserError("not authorised"))
|
||||||
}
|
}
|
||||||
message := ""
|
message := ""
|
||||||
|
@ -1769,7 +1795,7 @@ func clientWriter(conn *websocket.Conn, ch <-chan interface{}, done chan<- struc
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *webClient) Warn(oponly bool, message string) error {
|
func (c *webClient) Warn(oponly bool, message string) error {
|
||||||
if oponly && !c.permissions.Op {
|
if oponly && !member("op", c.permissions) {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -402,6 +402,7 @@ function setVisibility(id, visible) {
|
||||||
function setButtonsVisibility() {
|
function setButtonsVisibility() {
|
||||||
let connected = serverConnection && serverConnection.socket;
|
let connected = serverConnection && serverConnection.socket;
|
||||||
let permissions = serverConnection.permissions;
|
let permissions = serverConnection.permissions;
|
||||||
|
let present = permissions.indexOf('present') >= 0;
|
||||||
let local = !!findUpMedia('camera');
|
let local = !!findUpMedia('camera');
|
||||||
let canWebrtc = !(typeof RTCPeerConnection === 'undefined');
|
let canWebrtc = !(typeof RTCPeerConnection === 'undefined');
|
||||||
let canFile =
|
let canFile =
|
||||||
|
@ -413,19 +414,19 @@ function setButtonsVisibility() {
|
||||||
let mobilelayout = isMobileLayout();
|
let mobilelayout = isMobileLayout();
|
||||||
|
|
||||||
// don't allow multiple presentations
|
// don't allow multiple presentations
|
||||||
setVisibility('presentbutton', canWebrtc && permissions.present && !local);
|
setVisibility('presentbutton', canWebrtc && present && !local);
|
||||||
setVisibility('unpresentbutton', local);
|
setVisibility('unpresentbutton', local);
|
||||||
|
|
||||||
setVisibility('mutebutton', !connected || permissions.present);
|
setVisibility('mutebutton', !connected || present);
|
||||||
|
|
||||||
// allow multiple shared documents
|
// allow multiple shared documents
|
||||||
setVisibility('sharebutton', canWebrtc && permissions.present &&
|
setVisibility('sharebutton', canWebrtc && present &&
|
||||||
('getDisplayMedia' in navigator.mediaDevices));
|
('getDisplayMedia' in navigator.mediaDevices));
|
||||||
|
|
||||||
setVisibility('mediaoptions', permissions.present);
|
setVisibility('mediaoptions', present);
|
||||||
setVisibility('sendform', permissions.present);
|
setVisibility('sendform', present);
|
||||||
setVisibility('simulcastform', permissions.present);
|
setVisibility('simulcastform', present);
|
||||||
setVisibility('fileform', canFile && permissions.present);
|
setVisibility('fileform', canFile && present);
|
||||||
|
|
||||||
setVisibility('collapse-video', mediacount && mobilelayout);
|
setVisibility('collapse-video', mediacount && mobilelayout);
|
||||||
}
|
}
|
||||||
|
@ -2012,9 +2013,9 @@ function userMenu(elt) {
|
||||||
items.push({label: 'Send file', onClick: () => {
|
items.push({label: 'Send file', onClick: () => {
|
||||||
sendFile(id);
|
sendFile(id);
|
||||||
}});
|
}});
|
||||||
if(serverConnection.permissions.op) {
|
if(serverConnection.permissions.indexOf('op') >= 0) {
|
||||||
items.push({type: 'seperator'}); // sic
|
items.push({type: 'seperator'}); // sic
|
||||||
if(user.permissions.present)
|
if(user.permissions.indexOf('present') >= 0)
|
||||||
items.push({label: 'Forbid presenting', onClick: () => {
|
items.push({label: 'Forbid presenting', onClick: () => {
|
||||||
serverConnection.userAction('unpresent', id);
|
serverConnection.userAction('unpresent', id);
|
||||||
}});
|
}});
|
||||||
|
@ -2139,12 +2140,14 @@ function gotUser(id, kind) {
|
||||||
|
|
||||||
function displayUsername() {
|
function displayUsername() {
|
||||||
document.getElementById('userspan').textContent = username;
|
document.getElementById('userspan').textContent = username;
|
||||||
|
let op = serverConnection.permissions.indexOf('op') >= 0;
|
||||||
|
let present = serverConnection.permissions.indexOf('present') >= 0;
|
||||||
let text = '';
|
let text = '';
|
||||||
if(serverConnection.permissions.op && serverConnection.permissions.present)
|
if(op && present)
|
||||||
text = '(op, presenter)';
|
text = '(op, presenter)';
|
||||||
else if(serverConnection.permissions.op)
|
else if(op)
|
||||||
text = 'operator';
|
text = 'operator';
|
||||||
else if(serverConnection.permissions.present)
|
else if(present)
|
||||||
text = 'presenter';
|
text = 'presenter';
|
||||||
document.getElementById('permspan').textContent = text;
|
document.getElementById('permspan').textContent = text;
|
||||||
}
|
}
|
||||||
|
@ -2178,7 +2181,7 @@ function setTitle(title) {
|
||||||
/**
|
/**
|
||||||
* @this {ServerConnection}
|
* @this {ServerConnection}
|
||||||
* @param {string} group
|
* @param {string} group
|
||||||
* @param {Object<string,boolean>} perms
|
* @param {Array<string>} perms
|
||||||
* @param {Object<string,any>} status
|
* @param {Object<string,any>} status
|
||||||
* @param {Object<string,any>} data
|
* @param {Object<string,any>} data
|
||||||
* @param {string} message
|
* @param {string} message
|
||||||
|
@ -2226,7 +2229,8 @@ async function gotJoined(kind, group, perms, status, data, message) {
|
||||||
else
|
else
|
||||||
this.request(mapRequest(getSettings().request));
|
this.request(mapRequest(getSettings().request));
|
||||||
|
|
||||||
if(serverConnection.permissions.present && !findUpMedia('camera')) {
|
if(serverConnection.permissions.indexOf('present') >= 0 &&
|
||||||
|
!findUpMedia('camera')) {
|
||||||
if(present) {
|
if(present) {
|
||||||
if(present === 'mike')
|
if(present === 'mike')
|
||||||
updateSettings({video: ''});
|
updateSettings({video: ''});
|
||||||
|
@ -3050,14 +3054,14 @@ let commands = {};
|
||||||
|
|
||||||
function operatorPredicate() {
|
function operatorPredicate() {
|
||||||
if(serverConnection && serverConnection.permissions &&
|
if(serverConnection && serverConnection.permissions &&
|
||||||
serverConnection.permissions.op)
|
serverConnection.permissions.indexOf('op') >= 0)
|
||||||
return null;
|
return null;
|
||||||
return 'You are not an operator';
|
return 'You are not an operator';
|
||||||
}
|
}
|
||||||
|
|
||||||
function recordingPredicate() {
|
function recordingPredicate() {
|
||||||
if(serverConnection && serverConnection.permissions &&
|
if(serverConnection && serverConnection.permissions &&
|
||||||
serverConnection.permissions.record)
|
serverConnection.permissions.indexOf('record') >= 0)
|
||||||
return null;
|
return null;
|
||||||
return 'You are not allowed to record';
|
return 'You are not allowed to record';
|
||||||
}
|
}
|
||||||
|
|
|
@ -63,7 +63,7 @@ function newLocalId() {
|
||||||
/**
|
/**
|
||||||
* @typedef {Object} user
|
* @typedef {Object} user
|
||||||
* @property {string} username
|
* @property {string} username
|
||||||
* @property {Object<string,boolean>} permissions
|
* @property {Array<string>} permissions
|
||||||
* @property {Object<string,any>} data
|
* @property {Object<string,any>} data
|
||||||
* @property {Object<string,Object<string,boolean>>} down
|
* @property {Object<string,Object<string,boolean>>} down
|
||||||
*/
|
*/
|
||||||
|
@ -126,9 +126,9 @@ function ServerConnection() {
|
||||||
/**
|
/**
|
||||||
* The permissions granted to this connection.
|
* The permissions granted to this connection.
|
||||||
*
|
*
|
||||||
* @type {Object<string,boolean>}
|
* @type {Array<string>}
|
||||||
*/
|
*/
|
||||||
this.permissions = {};
|
this.permissions = [];
|
||||||
/**
|
/**
|
||||||
* userdata is a convenient place to attach data to a ServerConnection.
|
* userdata is a convenient place to attach data to a ServerConnection.
|
||||||
* It is not used by the library.
|
* It is not used by the library.
|
||||||
|
@ -164,7 +164,7 @@ function ServerConnection() {
|
||||||
*
|
*
|
||||||
* kind is one of 'join', 'fail', 'change' or 'leave'.
|
* kind is one of 'join', 'fail', 'change' or 'leave'.
|
||||||
*
|
*
|
||||||
* @type{(this: ServerConnection, kind: string, group: string, permissions: Object<string,boolean>, status: Object<string,any>, data: Object<string,any>, message: string) => void}
|
* @type{(this: ServerConnection, kind: string, group: string, permissions: Array<string>, status: Object<string,any>, data: Object<string,any>, message: string) => void}
|
||||||
*/
|
*/
|
||||||
this.onjoined = null;
|
this.onjoined = null;
|
||||||
/**
|
/**
|
||||||
|
@ -207,7 +207,7 @@ function ServerConnection() {
|
||||||
* @property {string} [password]
|
* @property {string} [password]
|
||||||
* @property {string} [token]
|
* @property {string} [token]
|
||||||
* @property {boolean} [privileged]
|
* @property {boolean} [privileged]
|
||||||
* @property {Object<string,boolean>} [permissions]
|
* @property {Array<string>} [permissions]
|
||||||
* @property {Object<string,any>} [status]
|
* @property {Object<string,any>} [status]
|
||||||
* @property {Object<string,any>} [data]
|
* @property {Object<string,any>} [data]
|
||||||
* @property {string} [group]
|
* @property {string} [group]
|
||||||
|
@ -271,7 +271,7 @@ ServerConnection.prototype.connect = async function(url) {
|
||||||
resolve(sc);
|
resolve(sc);
|
||||||
};
|
};
|
||||||
this.socket.onclose = function(e) {
|
this.socket.onclose = function(e) {
|
||||||
sc.permissions = {};
|
sc.permissions = [];
|
||||||
for(let id in sc.up) {
|
for(let id in sc.up) {
|
||||||
let c = sc.up[id];
|
let c = sc.up[id];
|
||||||
c.close();
|
c.close();
|
||||||
|
@ -286,7 +286,7 @@ ServerConnection.prototype.connect = async function(url) {
|
||||||
sc.onuser.call(sc, id, 'delete');
|
sc.onuser.call(sc, id, 'delete');
|
||||||
}
|
}
|
||||||
if(sc.group && sc.onjoined)
|
if(sc.group && sc.onjoined)
|
||||||
sc.onjoined.call(sc, 'leave', sc.group, {}, {}, {}, '');
|
sc.onjoined.call(sc, 'leave', sc.group, [], {}, {}, '');
|
||||||
sc.group = null;
|
sc.group = null;
|
||||||
sc.username = null;
|
sc.username = null;
|
||||||
if(sc.onclose)
|
if(sc.onclose)
|
||||||
|
@ -337,7 +337,7 @@ ServerConnection.prototype.connect = async function(url) {
|
||||||
}
|
}
|
||||||
if(sc.onjoined)
|
if(sc.onjoined)
|
||||||
sc.onjoined.call(sc, m.kind, m.group,
|
sc.onjoined.call(sc, m.kind, m.group,
|
||||||
m.permissions || {},
|
m.permissions || [],
|
||||||
m.status, m.data,
|
m.status, m.data,
|
||||||
m.value || null);
|
m.value || null);
|
||||||
break;
|
break;
|
||||||
|
@ -348,7 +348,7 @@ ServerConnection.prototype.connect = async function(url) {
|
||||||
console.warn(`Duplicate user ${m.id} ${m.username}`);
|
console.warn(`Duplicate user ${m.id} ${m.username}`);
|
||||||
sc.users[m.id] = {
|
sc.users[m.id] = {
|
||||||
username: m.username,
|
username: m.username,
|
||||||
permissions: m.permissions || {},
|
permissions: m.permissions || [],
|
||||||
data: m.data || {},
|
data: m.data || {},
|
||||||
down: {},
|
down: {},
|
||||||
};
|
};
|
||||||
|
@ -358,13 +358,13 @@ ServerConnection.prototype.connect = async function(url) {
|
||||||
console.warn(`Unknown user ${m.id} ${m.username}`);
|
console.warn(`Unknown user ${m.id} ${m.username}`);
|
||||||
sc.users[m.id] = {
|
sc.users[m.id] = {
|
||||||
username: m.username,
|
username: m.username,
|
||||||
permissions: m.permissions || {},
|
permissions: m.permissions || [],
|
||||||
data: m.data || {},
|
data: m.data || {},
|
||||||
down: {},
|
down: {},
|
||||||
};
|
};
|
||||||
} else {
|
} else {
|
||||||
sc.users[m.id].username = m.username;
|
sc.users[m.id].username = m.username;
|
||||||
sc.users[m.id].permissions = m.permissions || {};
|
sc.users[m.id].permissions = m.permissions || [];
|
||||||
sc.users[m.id].data = m.data || {};
|
sc.users[m.id].data = m.data || {};
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
|
@ -105,7 +105,7 @@ func getKey(header map[string]interface{}, keys []map[string]interface{}) (inter
|
||||||
return nil, errors.New("key not found")
|
return nil, errors.New("key not found")
|
||||||
}
|
}
|
||||||
|
|
||||||
func Valid(username, token string, keys []map[string]interface{}) ([]string, map[string]interface{}, error) {
|
func Valid(username, token string, keys []map[string]interface{}) ([]string, []string, error) {
|
||||||
tok, err := jwt.Parse(token, func(t *jwt.Token) (interface{}, error) {
|
tok, err := jwt.Parse(token, func(t *jwt.Token) (interface{}, error) {
|
||||||
return getKey(t.Header, keys)
|
return getKey(t.Header, keys)
|
||||||
})
|
})
|
||||||
|
@ -118,19 +118,33 @@ func Valid(username, token string, keys []map[string]interface{}) ([]string, map
|
||||||
if !ok || sub != username {
|
if !ok || sub != username {
|
||||||
return nil, nil, ErrUnexpectedSub
|
return nil, nil, ErrUnexpectedSub
|
||||||
}
|
}
|
||||||
aud, ok := claims["aud"]
|
|
||||||
var res []string
|
var aud []string
|
||||||
if ok {
|
if a, ok := claims["aud"]; ok && a != nil {
|
||||||
switch aud := aud.(type) {
|
switch a := a.(type) {
|
||||||
case string:
|
case string:
|
||||||
res = []string{aud}
|
aud = []string{a}
|
||||||
case []string:
|
case []string:
|
||||||
res = aud
|
aud = a
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
perms, ok := claims["permissions"].(map[string]interface{})
|
|
||||||
if !ok {
|
var perms []string
|
||||||
return nil, nil, errors.New("invalid 'permissions' field")
|
if p, ok := claims["permissions"]; ok && p != nil {
|
||||||
|
pp, ok := p.([]interface{})
|
||||||
|
if !ok {
|
||||||
|
return nil, nil,
|
||||||
|
errors.New("invalid 'permissions' field")
|
||||||
|
}
|
||||||
|
perms = make([]string, len(pp))
|
||||||
|
for i, v := range pp {
|
||||||
|
w, ok := v.(string)
|
||||||
|
if !ok {
|
||||||
|
return nil, nil,
|
||||||
|
errors.New("invalid 'permissions' field")
|
||||||
|
}
|
||||||
|
perms[i] = w
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return res, perms, nil
|
return aud, perms, nil
|
||||||
}
|
}
|
||||||
|
|
|
@ -58,13 +58,7 @@ func TestES256(t *testing.T) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestValid(t *testing.T) {
|
func TestValid(t *testing.T) {
|
||||||
key := `{
|
key := `{"alg":"HS256","k":"H7pCkktUl5KyPCZ7CKw09y1j460tfIv4dRcS1XstUKY","key_ops":["sign","verify"],"kty":"oct"}`
|
||||||
"kty":"EC",
|
|
||||||
"alg":"ES256",
|
|
||||||
"crv":"P-256",
|
|
||||||
"x":"CBo2DHISffe8bVr6bNspCiHK3zK9pfMGfWtpHnk9-Lw",
|
|
||||||
"y":"sD5dQ-bJu8AfRGLfA6MigQyUIOQHcYx6HQOdfIbLjHo"
|
|
||||||
}`
|
|
||||||
var k map[string]interface{}
|
var k map[string]interface{}
|
||||||
err := json.Unmarshal([]byte(key), &k)
|
err := json.Unmarshal([]byte(key), &k)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -73,7 +67,7 @@ func TestValid(t *testing.T) {
|
||||||
|
|
||||||
keys := []map[string]interface{}{k}
|
keys := []map[string]interface{}{k}
|
||||||
|
|
||||||
goodToken := "eyJ0eXAiOiJKV1QiLCJhbGciOiJFUzI1NiJ9.eyJzdWIiOiJqb2huIiwiYXVkIjoiaHR0cHM6Ly9nYWxlbmUub3JnOjg0NDMvZ3JvdXAvYXV0aC8iLCJwZXJtaXNzaW9ucyI6eyJwcmVzZW50Ijp0cnVlfSwiaWF0IjoxNjQ1MTk1MzkxLCJleHAiOjIyNzU5MTUzOTEsImlzcyI6Imh0dHA6Ly9sb2NhbGhvc3Q6MTIzNC8ifQ.PMgfwYwSLSFIfcNJdOEfHEZ41HM2CzbATuS1fTxncbaGyX-xXq7d9V04enXpLOMGnAlsZpOJvd7eJN2mngJMAg"
|
goodToken := "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJzdWIiOiJqb2huIiwiYXVkIjoiaHR0cHM6Ly9nYWxlbmUub3JnOjg0NDMvZ3JvdXAvYXV0aC8iLCJwZXJtaXNzaW9ucyI6WyJwcmVzZW50Il0sImlhdCI6MTY0NTMxMDI5NCwiZXhwIjoyOTA2NzUwMjk0LCJpc3MiOiJodHRwOi8vbG9jYWxob3N0OjEyMzQvIn0.6xXpgBkBMn4PSBpnwYHb-gRn_Q97Yq9DoKkAf2_6iwc"
|
||||||
|
|
||||||
aud, perms, err := Valid("john", goodToken, keys)
|
aud, perms, err := Valid("john", goodToken, keys)
|
||||||
|
|
||||||
|
@ -83,9 +77,7 @@ func TestValid(t *testing.T) {
|
||||||
if !reflect.DeepEqual(aud, []string{"https://galene.org:8443/group/auth/"}) {
|
if !reflect.DeepEqual(aud, []string{"https://galene.org:8443/group/auth/"}) {
|
||||||
t.Errorf("Unexpected aud: %v", aud)
|
t.Errorf("Unexpected aud: %v", aud)
|
||||||
}
|
}
|
||||||
if !reflect.DeepEqual(
|
if !reflect.DeepEqual(perms, []string{"present"}) {
|
||||||
perms, map[string]interface{}{"present": true},
|
|
||||||
) {
|
|
||||||
t.Errorf("Unexpected perms: %v", perms)
|
t.Errorf("Unexpected perms: %v", perms)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -95,7 +87,7 @@ func TestValid(t *testing.T) {
|
||||||
t.Errorf("Token should have bad username")
|
t.Errorf("Token should have bad username")
|
||||||
}
|
}
|
||||||
|
|
||||||
badToken := "eyJ0eXAiOiJKV1QiLCJhbGciOiJFUzI1NiJ9.eyJzdWIiOiJqb2huIiwiYXVkIjoiaHR0cHM6Ly9nYWxlbmUub3JnOjg0NDMvZ3JvdXAvYXV0aC8iLCJwZXJtaXNzaW9ucyI6eyJwcmVzZW50Ijp0cnVlfSwiaWF0IjoxNjQ1MTk2MDE5LCJleHAiOjIyNjAzNjQwMTksImlzcyI6Imh0dHA6Ly9sb2NhbGhvc3Q6MTIzNC8ifQ.4TN5zxzuKeNIw0rX0yirEkVYF1d0FHI_Lezmsa27ayi0R4ocSgTZ3q2bmlACXvyuoBqEEbuP4e77BUbGCHmpSg"
|
badToken := "eyJ0eXAiOiJKV1QiLCJhbGciOiJub25lIn0.eyJzdWIiOiJqb2huIiwiYXVkIjoiaHR0cHM6Ly9nYWxlbmUub3JnOjg0NDMvZ3JvdXAvYXV0aC8iLCJwZXJtaXNzaW9ucyI6WyJwcmVzZW50Il0sImlhdCI6MTY0NTMxMDQ2OSwiZXhwIjoyOTA2NzUwNDY5LCJpc3MiOiJodHRwOi8vbG9jYWxob3N0OjEyMzQvIn0."
|
||||||
|
|
||||||
_, _, err = Valid("john", badToken, keys)
|
_, _, err = Valid("john", badToken, keys)
|
||||||
|
|
||||||
|
@ -104,7 +96,7 @@ func TestValid(t *testing.T) {
|
||||||
t.Errorf("Token should fail")
|
t.Errorf("Token should fail")
|
||||||
}
|
}
|
||||||
|
|
||||||
expiredToken := "eyJ0eXAiOiJKV1QiLCJhbGciOiJFUzI1NiJ9.eyJzdWIiOiJqb2huIiwiYXVkIjoiaHR0cHM6Ly9nYWxlbmUub3JnOjg0NDMvZ3JvdXAvYXV0aC8iLCJwZXJtaXNzaW9ucyI6eyJwcmVzZW50Ijp0cnVlfSwiaWF0IjoxNjQ1MTk1NTY3LCJleHAiOjE2NDUxOTU1OTcsImlzcyI6Imh0dHA6Ly9sb2NhbGhvc3Q6MTIzNC8ifQ.GXcLeyNVr5cnZjIECENyjMLH1HyNKWKkHMc9onvqA_RVYMyDLeeR_3NKH9Y7eKSXWC8jhatDWtH7Ed3KdsSxAA"
|
expiredToken := "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJzdWIiOiJqb2huIiwiYXVkIjoiaHR0cHM6Ly9nYWxlbmUub3JnOjg0NDMvZ3JvdXAvYXV0aC8iLCJwZXJtaXNzaW9ucyI6WyJwcmVzZW50Il0sImlhdCI6MTY0NTMxMDMyMiwiZXhwIjoxNjQ1MzEwMzUyLCJpc3MiOiJodHRwOi8vbG9jYWxob3N0OjEyMzQvIn0.jyqRhoV6iK54SvlP33Fy630aDo-sLNmKKi1kcfqs378"
|
||||||
|
|
||||||
_, _, err = Valid("john", expiredToken, keys)
|
_, _, err = Valid("john", expiredToken, keys)
|
||||||
|
|
||||||
|
@ -112,8 +104,7 @@ func TestValid(t *testing.T) {
|
||||||
t.Errorf("Token should be expired")
|
t.Errorf("Token should be expired")
|
||||||
}
|
}
|
||||||
|
|
||||||
noneToken := "eyJ0eXAiOiJKV1QiLCJhbGciOiJub25lIn0.eyJzdWIiOiJqb2huIiwiYXVkIjoiaHR0cHM6Ly9nYWxlbmUub3JnOjg0NDMvZ3JvdXAvYXV0aC8iLCJwZXJtaXNzaW9ucyI6eyJwcmVzZW50Ijp0cnVlfSwiaWF0IjoxNjQ1MTk1NzgyLCJleHAiOjIyNjAzNjM3ODIsImlzcyI6Imh0dHA6Ly9sb2NhbGhvc3Q6MTIzNC8ifQ."
|
noneToken := "eyJ0eXAiOiJKV1QiLCJhbGciOiJub25lIn0.eyJzdWIiOiJqb2huIiwiYXVkIjoiaHR0cHM6Ly9nYWxlbmUub3JnOjg0NDMvZ3JvdXAvYXV0aC8iLCJwZXJtaXNzaW9ucyI6WyJwcmVzZW50Il0sImlhdCI6MTY0NTMxMDQwMSwiZXhwIjoxNjQ1MzEwNDMxLCJpc3MiOiJodHRwOi8vbG9jYWxob3N0OjEyMzQvIn0."
|
||||||
|
|
||||||
_, _, err = Valid("john", noneToken, keys)
|
_, _, err = Valid("john", noneToken, keys)
|
||||||
if err == nil {
|
if err == nil {
|
||||||
t.Errorf("Unsigned token should fail")
|
t.Errorf("Unsigned token should fail")
|
||||||
|
|
|
@ -592,7 +592,16 @@ func checkGroupPermissions(w http.ResponseWriter, r *http.Request, groupname str
|
||||||
Password: pass,
|
Password: pass,
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
if err != nil || !p.Record {
|
record := false
|
||||||
|
if err == nil {
|
||||||
|
for _, v := range p {
|
||||||
|
if v == "record" {
|
||||||
|
record = true
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if err != nil || !record {
|
||||||
if err == group.ErrNotAuthorised {
|
if err == group.ErrNotAuthorised {
|
||||||
time.Sleep(200 * time.Millisecond)
|
time.Sleep(200 * time.Millisecond)
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue