mirror of
https://github.com/jech/galene.git
synced 2024-11-22 08:35:57 +01:00
Add protocol messages for managing tokens.
This commit is contained in:
parent
a6314a7384
commit
8aa95f5e22
1 changed files with 218 additions and 0 deletions
|
@ -1,6 +1,8 @@
|
||||||
package rtpconn
|
package rtpconn
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
crand "crypto/rand"
|
||||||
|
"encoding/base64"
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
@ -17,6 +19,7 @@ import (
|
||||||
"github.com/jech/galene/estimator"
|
"github.com/jech/galene/estimator"
|
||||||
"github.com/jech/galene/group"
|
"github.com/jech/galene/group"
|
||||||
"github.com/jech/galene/ice"
|
"github.com/jech/galene/ice"
|
||||||
|
"github.com/jech/galene/token"
|
||||||
)
|
)
|
||||||
|
|
||||||
func errorToWSCloseMessage(id string, err error) (*clientMessage, []byte) {
|
func errorToWSCloseMessage(id string, err error) (*clientMessage, []byte) {
|
||||||
|
@ -1700,6 +1703,124 @@ func handleClientMessage(c *webClient, m clientMessage) error {
|
||||||
))
|
))
|
||||||
}
|
}
|
||||||
g.UpdateData(data)
|
g.UpdateData(data)
|
||||||
|
case "maketoken":
|
||||||
|
terror := func(e, m string) error {
|
||||||
|
return c.write(clientMessage{
|
||||||
|
Type: "usermessage",
|
||||||
|
Kind: "token",
|
||||||
|
Privileged: true,
|
||||||
|
Error: e,
|
||||||
|
Value: m,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
if !member("token", c.permissions) {
|
||||||
|
return terror("not-authorised", "not authorised")
|
||||||
|
}
|
||||||
|
tok, err := parseStatefulToken(m.Value)
|
||||||
|
if err != nil {
|
||||||
|
return terror("not-authorised", "not authorised")
|
||||||
|
}
|
||||||
|
|
||||||
|
if tok.Token == "" {
|
||||||
|
buf := make([]byte, 8)
|
||||||
|
crand.Read(buf)
|
||||||
|
tok.Token =
|
||||||
|
base64.RawURLEncoding.EncodeToString(buf)
|
||||||
|
} else {
|
||||||
|
return terror("error", "client specified token")
|
||||||
|
}
|
||||||
|
|
||||||
|
if tok.Group != c.group.Name() {
|
||||||
|
return terror("error", "wrong group in token")
|
||||||
|
}
|
||||||
|
|
||||||
|
if tok.Expires == nil {
|
||||||
|
return terror("error", "token doesn't expire")
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, p := range tok.Permissions {
|
||||||
|
if !member(p, c.permissions) {
|
||||||
|
return terror(
|
||||||
|
"not-authorised",
|
||||||
|
"not authorised",
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
new, err := token.Add(tok)
|
||||||
|
if err != nil {
|
||||||
|
return terror("error", err.Error())
|
||||||
|
}
|
||||||
|
c.write(clientMessage{
|
||||||
|
Type: "usermessage",
|
||||||
|
Kind: "token",
|
||||||
|
Privileged: true,
|
||||||
|
Value: new,
|
||||||
|
})
|
||||||
|
case "edittoken":
|
||||||
|
terror := func(e, m string) error {
|
||||||
|
return c.write(clientMessage{
|
||||||
|
Type: "usermessage",
|
||||||
|
Kind: "token",
|
||||||
|
Privileged: true,
|
||||||
|
Error: e,
|
||||||
|
Value: m,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
if !member("op", c.permissions) ||
|
||||||
|
!member("token", c.permissions) {
|
||||||
|
return terror("not-authorised", "not authorised")
|
||||||
|
}
|
||||||
|
tok, err := parseStatefulToken(m.Value)
|
||||||
|
if err != nil {
|
||||||
|
return terror("error", err.Error())
|
||||||
|
}
|
||||||
|
if tok.Group != "" || tok.Username != nil ||
|
||||||
|
tok.Permissions != nil ||
|
||||||
|
tok.NotBefore != nil {
|
||||||
|
return terror(
|
||||||
|
"error", "this field cannot be edited",
|
||||||
|
)
|
||||||
|
}
|
||||||
|
if tok.Expires == nil {
|
||||||
|
return terror("error", "trying to edit nothing")
|
||||||
|
}
|
||||||
|
new, err := token.Edit(
|
||||||
|
c.group.Name(), tok.Token, *tok.Expires,
|
||||||
|
)
|
||||||
|
if err != nil {
|
||||||
|
return terror("error", err.Error())
|
||||||
|
}
|
||||||
|
c.write(clientMessage{
|
||||||
|
Type: "usermessage",
|
||||||
|
Kind: "token",
|
||||||
|
Privileged: true,
|
||||||
|
Value: new,
|
||||||
|
})
|
||||||
|
case "listtokens":
|
||||||
|
terror := func(e, m string) error {
|
||||||
|
return c.write(clientMessage{
|
||||||
|
Type: "usermessage",
|
||||||
|
Kind: "tokenlist",
|
||||||
|
Privileged: true,
|
||||||
|
Error: e,
|
||||||
|
Value: m,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
if !member("op", c.permissions) ||
|
||||||
|
!member("token", c.permissions) {
|
||||||
|
return terror("not-authorised", "not authorised")
|
||||||
|
}
|
||||||
|
tokens, err := token.List(c.group.Name())
|
||||||
|
if err != nil {
|
||||||
|
return terror("error", err.Error())
|
||||||
|
}
|
||||||
|
c.write(clientMessage{
|
||||||
|
Type: "usermessage",
|
||||||
|
Kind: "tokenlist",
|
||||||
|
Privileged: true,
|
||||||
|
Value: tokens,
|
||||||
|
})
|
||||||
default:
|
default:
|
||||||
return group.UserError("unknown group action")
|
return group.UserError("unknown group action")
|
||||||
}
|
}
|
||||||
|
@ -1778,6 +1899,103 @@ func handleClientMessage(c *webClient, m clientMessage) error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func parseStatefulToken(value interface{}) (*token.Stateful, error) {
|
||||||
|
data, ok := value.(map[string]interface{})
|
||||||
|
if !ok || data == nil {
|
||||||
|
return nil, errors.New("bad token value")
|
||||||
|
}
|
||||||
|
parseString := func(key string) (*string, error) {
|
||||||
|
v := data[key]
|
||||||
|
if v == nil {
|
||||||
|
return nil, nil
|
||||||
|
}
|
||||||
|
vv, ok := v.(string)
|
||||||
|
if !ok {
|
||||||
|
return nil, errors.New("bad string value")
|
||||||
|
}
|
||||||
|
return &vv, nil
|
||||||
|
}
|
||||||
|
parseStringList := func(key string) ([]string, error) {
|
||||||
|
v := data[key]
|
||||||
|
if v == nil {
|
||||||
|
return nil, nil
|
||||||
|
}
|
||||||
|
vv, ok := v.([]interface{})
|
||||||
|
if !ok {
|
||||||
|
return nil, errors.New("bad string list")
|
||||||
|
}
|
||||||
|
vvv := make([]string, 0, len(vv))
|
||||||
|
for _, s := range vv {
|
||||||
|
ss, ok := s.(string)
|
||||||
|
if !ok {
|
||||||
|
return nil, errors.New("bad string list")
|
||||||
|
}
|
||||||
|
vvv = append(vvv, ss)
|
||||||
|
}
|
||||||
|
return vvv, nil
|
||||||
|
}
|
||||||
|
parseTime := func(key string) (*time.Time, error) {
|
||||||
|
v := data[key]
|
||||||
|
if v == nil {
|
||||||
|
return nil, nil
|
||||||
|
}
|
||||||
|
switch v := v.(type) {
|
||||||
|
case string:
|
||||||
|
vv, err := time.Parse(time.RFC3339, v)
|
||||||
|
if err != nil {
|
||||||
|
return nil, errors.New("bad time value")
|
||||||
|
}
|
||||||
|
return &vv, nil
|
||||||
|
case float64: // relative time
|
||||||
|
vv := time.Now().Add(time.Duration(v) * time.Millisecond)
|
||||||
|
return &vv, nil
|
||||||
|
default:
|
||||||
|
return nil, errors.New("bad time value")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
t, err := parseString("token")
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
tt := ""
|
||||||
|
if t != nil {
|
||||||
|
tt = *t
|
||||||
|
}
|
||||||
|
u, err := parseString("username")
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
g, err := parseString("group")
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
gg := ""
|
||||||
|
if g != nil {
|
||||||
|
gg = *g
|
||||||
|
}
|
||||||
|
p, err := parseStringList("permissions")
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
e, err := parseTime("expires")
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
n, err := parseTime("not-before")
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return &token.Stateful{
|
||||||
|
Token: tt,
|
||||||
|
Group: gg,
|
||||||
|
Username: u,
|
||||||
|
Permissions: p,
|
||||||
|
Expires: e,
|
||||||
|
NotBefore: n,
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
|
||||||
func clientReader(conn *websocket.Conn, read chan<- interface{}, done <-chan struct{}) {
|
func clientReader(conn *websocket.Conn, read chan<- interface{}, done <-chan struct{}) {
|
||||||
defer close(read)
|
defer close(read)
|
||||||
for {
|
for {
|
||||||
|
|
Loading…
Reference in a new issue