diff --git a/diskwriter/diskwriter.go b/diskwriter/diskwriter.go index 80326d7..02233b4 100644 --- a/diskwriter/diskwriter.go +++ b/diskwriter/diskwriter.go @@ -101,7 +101,7 @@ func (client *Client) Close() error { return nil } -func (client *Client) Kick(id, user, message string) error { +func (client *Client) Kick(id string, user *string, message string) error { err := client.Close() group.DelClient(client) return err diff --git a/group/client.go b/group/client.go index 9dab255..2215a34 100644 --- a/group/client.go +++ b/group/client.go @@ -83,7 +83,7 @@ type ClientPattern struct { type ClientCredentials struct { System bool - Username string + Username *string Password string Token string } @@ -100,5 +100,5 @@ type Client interface { RequestConns(target Client, g *Group, id string) error Joined(group, kind string) error PushClient(group, kind, id, username string, perms []string, data map[string]interface{}) error - Kick(id, user, message string) error + Kick(id string, user *string, message string) error } diff --git a/group/group.go b/group/group.go index 74f168f..3eb43ae 100644 --- a/group/group.go +++ b/group/group.go @@ -36,7 +36,7 @@ func (err UserError) Error() string { type KickError struct { Id string - Username string + Username *string Message string } @@ -45,8 +45,8 @@ func (err KickError) Error() string { if err.Message != "" { m += " (" + err.Message + ")" } - if err.Username != "" { - m += " by " + err.Username + if err.Username != nil && *err.Username != "" { + m += " by " + *err.Username } return m } @@ -59,7 +59,7 @@ func (err ProtocolError) Error() string { type ChatHistoryEntry struct { Id string - User string + User *string Time time.Time Kind string Value interface{} @@ -625,9 +625,8 @@ func AddClient(group string, c Client, creds ClientCredentials) (*Group, error) c.PushClient(g.Name(), "add", c.Id(), u, p, s) for _, cc := range clients { pp := cc.Permissions() - c.PushClient( - g.Name(), "add", cc.Id(), cc.Username(), pp, cc.Data(), - ) + uu := cc.Username() + c.PushClient(g.Name(), "add", cc.Id(), uu, pp, cc.Data()) cc.PushClient(g.Name(), "add", id, u, p, s) } @@ -679,7 +678,7 @@ func DelClient(c Client) { c.Joined(g.Name(), "leave") for _, cc := range clients { cc.PushClient( - g.Name(), "delete", c.Id(), "", nil, nil, + g.Name(), "delete", c.Id(), c.Username(), nil, nil, ) } autoLockKick(g) @@ -729,7 +728,7 @@ func (g *Group) Range(f func(c Client) bool) { func kickall(g *Group, message string) { g.Range(func(c Client) bool { - c.Kick("", "", message) + c.Kick("", nil, message) return true }) } @@ -768,7 +767,7 @@ func (g *Group) ClearChatHistory() { g.history = nil } -func (g *Group) AddToChatHistory(id, user string, time time.Time, kind string, value interface{}) { +func (g *Group) AddToChatHistory(id string, user *string, time time.Time, kind string, value interface{}) { g.mu.Lock() defer g.mu.Unlock() @@ -810,9 +809,14 @@ func (g *Group) GetChatHistory() []ChatHistoryEntry { } func matchClient(creds ClientCredentials, users []ClientPattern) (bool, bool) { + if creds.Username == nil { + return false, false + } + username := *creds.Username + matched := false for _, u := range users { - if u.Username == creds.Username { + if u.Username == username { matched = true if u.Password == nil { return true, true @@ -1102,7 +1106,10 @@ func readDescription(name string) (*Description, error) { func (g *Group) getPasswordPermission(creds ClientCredentials) ([]string, error) { desc := g.description - if !desc.AllowAnonymous && creds.Username == "" { + if creds.Username == nil { + return nil, errors.New("username not provided") + } + if !desc.AllowAnonymous && *creds.Username == "" { return nil, ErrAnonymousNotAuthorised } if found, good := matchClient(creds, desc.Op); found { @@ -1146,17 +1153,19 @@ func (g *Group) getPermission(creds ClientCredentials) (string, []string, error) } username, perms, err = - tok.Check(conf.CanonicalHost, g.name, &creds.Username) + tok.Check(conf.CanonicalHost, g.name, creds.Username) if err != nil { return "", nil, err } - } else { + } else if creds.Username != nil { + username = *creds.Username var err error - username = creds.Username perms, err = g.getPasswordPermission(creds) if err != nil { return "", nil, err } + } else { + return "", nil, errors.New("neither username nor token provided") } return username, perms, nil diff --git a/group/group_test.go b/group/group_test.go index f7c794b..b6e5f07 100644 --- a/group/group_test.go +++ b/group/group_test.go @@ -51,8 +51,9 @@ func TestChatHistory(t *testing.T) { g := Group{ description: &Description{}, } + user := "user" for i := 0; i < 2*maxChatHistory; i++ { - g.AddToChatHistory("id", "user", time.Now(), "", + g.AddToChatHistory("id", &user, time.Now(), "", fmt.Sprintf("%v", i), ) } @@ -108,10 +109,15 @@ func TestDescriptionJSON(t *testing.T) { } } +var jch = "jch" +var john = "john" +var james = "james" +var paul = "paul" + var badClients = []ClientCredentials{ - {Username: "jch", Password: "foo"}, - {Username: "john", Password: "foo"}, - {Username: "james", Password: "foo"}, + {Username: &jch, Password: "foo"}, + {Username: &john, Password: "foo"}, + {Username: &james, Password: "foo"}, } type credPerm struct { @@ -121,23 +127,23 @@ type credPerm struct { var goodClients = []credPerm{ { - ClientCredentials{Username: "jch", Password: "topsecret"}, + ClientCredentials{Username: &jch, Password: "topsecret"}, []string{"op", "present"}, }, { - ClientCredentials{Username: "john", Password: "secret"}, + ClientCredentials{Username: &john, Password: "secret"}, []string{"present"}, }, { - ClientCredentials{Username: "john", Password: "secret2"}, + ClientCredentials{Username: &john, Password: "secret2"}, []string{"present"}, }, { - ClientCredentials{Username: "james", Password: "secret3"}, + ClientCredentials{Username: &james, Password: "secret3"}, nil, }, { - ClientCredentials{Username: "paul", Password: "secret3"}, + ClientCredentials{Username: &paul, Password: "secret3"}, nil, }, } @@ -150,7 +156,7 @@ func TestPermissions(t *testing.T) { } for _, c := range badClients { - t.Run("bad "+c.Username, func(t *testing.T) { + t.Run("bad "+*c.Username, func(t *testing.T) { _, p, err := g.GetPermission(c) if err != ErrNotAuthorised { t.Errorf("GetPermission %v: %v %v", c, err, p) @@ -159,11 +165,11 @@ func TestPermissions(t *testing.T) { } for _, cp := range goodClients { - t.Run("good "+cp.c.Username, func(t *testing.T) { + t.Run("good "+*cp.c.Username, func(t *testing.T) { u, p, err := g.GetPermission(cp.c) if err != nil { t.Errorf("GetPermission %v: %v", cp.c, err) - } else if u != cp.c.Username || + } else if u != *cp.c.Username || !reflect.DeepEqual(p, cp.p) { t.Errorf("%v: got %v %v, expected %v", cp.c, u, p, cp.p) diff --git a/rtpconn/webclient.go b/rtpconn/webclient.go index ddbd80e..2e82a49 100644 --- a/rtpconn/webclient.go +++ b/rtpconn/webclient.go @@ -102,7 +102,7 @@ func (c *webClient) SetPermissions(perms []string) { c.permissions = perms } -func (c *webClient) PushClient(group, kind, id, username string, perms []string, data map[string]interface{}) error { +func (c *webClient) PushClient(group, kind, id string, username string, perms []string, data map[string]interface{}) error { return c.action(pushClientAction{ group, kind, id, username, perms, data, }) @@ -117,7 +117,7 @@ type clientMessage struct { Replace string `json:"replace,omitempty"` Source string `json:"source,omitempty"` Dest string `json:"dest,omitempty"` - Username string `json:"username,omitempty"` + Username *string `json:"username,omitempty"` Password string `json:"password,omitempty"` Token string `json:"token,omitempty"` Privileged bool `json:"privileged,omitempty"` @@ -555,7 +555,7 @@ func negotiate(c *webClient, down *rtpDownConnection, restartIce bool, replace s Label: down.remote.Label(), Replace: replace, Source: source, - Username: username, + Username: &username, SDP: down.pc.LocalDescription().SDP, }) } @@ -930,7 +930,7 @@ type joinedAction struct { type kickAction struct { id string - username string + username *string message string } @@ -1160,11 +1160,12 @@ func handleAction(c *webClient, a interface{}) error { return nil } perms := append([]string(nil), a.permissions...) + username := a.username return c.write(clientMessage{ Type: "user", Kind: a.kind, Id: a.id, - Username: a.username, + Username: &username, Permissions: perms, Data: a.data, }) @@ -1181,11 +1182,12 @@ func handleAction(c *webClient, a interface{}) error { } } perms := append([]string(nil), c.permissions...) + username := c.username err := c.write(clientMessage{ Type: "joined", Kind: a.kind, Group: a.group, - Username: c.username, + Username: &username, Permissions: perms, Status: status, Data: data, @@ -1222,11 +1224,12 @@ func handleAction(c *webClient, a interface{}) error { } perms := append([]string(nil), c.permissions...) status := g.Status(true, "") + username := c.username c.write(clientMessage{ Type: "joined", Kind: "change", Group: g.Name(), - Username: c.username, + Username: &username, Permissions: perms, Status: &status, RTCConfiguration: ice.ICEConfiguration(), @@ -1360,7 +1363,7 @@ func setPermissions(g *group.Group, id string, perm string) error { return c.action(permissionsChangedAction{}) } -func (c *webClient) Kick(id, user, message string) error { +func (c *webClient) Kick(id string, user *string, message string) error { return c.action(kickAction{id, user, message}) } @@ -1368,7 +1371,7 @@ func (c *webClient) Joined(group, kind string) error { return c.action(joinedAction{group, kind}) } -func kickClient(g *group.Group, id, user, dest string, message string) error { +func kickClient(g *group.Group, id string, user *string, dest string, message string) error { client := g.GetClient(dest) if client == nil { return group.UserError("no such user") @@ -1385,8 +1388,8 @@ func handleClientMessage(c *webClient, m clientMessage) error { } if m.Type != "join" { - if m.Username != "" { - if m.Username != c.Username() { + if m.Username != nil { + if *m.Username != c.Username() { return group.ProtocolError("spoofed username") } } @@ -1411,7 +1414,6 @@ func handleClientMessage(c *webClient, m clientMessage) error { "cannot join multiple groups", ) } - c.username = m.Username c.data = m.Data g, err := group.AddClient(m.Group, c, group.ClientCredentials{ @@ -1435,23 +1437,25 @@ func handleClientMessage(c *webClient, m clientMessage) error { s = "internal server error" log.Printf("Join group: %v", err) } + username := c.username return c.write(clientMessage{ Type: "joined", Kind: "fail", Error: e, Group: m.Group, - Username: c.username, + Username: &username, Value: s, }) } if redirect := g.Description().Redirect; redirect != "" { // We normally redirect at the HTTP level, but the group // description could have been edited in the meantime. + username := c.username return c.write(clientMessage{ Type: "joined", Kind: "redirect", Group: m.Group, - Username: c.username, + Username: &username, Value: redirect, }) } @@ -1677,10 +1681,11 @@ func handleClientMessage(c *webClient, m clientMessage) error { s = s + fmt.Sprintf("%v (%v client%v)\n", sg.Name, sg.Clients, plural) } + username := "Server" c.write(clientMessage{ Type: "chat", Dest: c.id, - Username: "Server", + Username: &username, Time: time.Now().Format(time.RFC3339), Value: s, }) diff --git a/webserver/webserver.go b/webserver/webserver.go index c8b9236..3b1d21c 100644 --- a/webserver/webserver.go +++ b/webserver/webserver.go @@ -642,7 +642,7 @@ func checkGroupPermissions(w http.ResponseWriter, r *http.Request, groupname str _, p, err := g.GetPermission( group.ClientCredentials{ - Username: user, + Username: &user, Password: pass, }, )