Adding some hardening to user joining

Client sends the server a object to join instead of a message
server can send a message to notify the user

closes #57
This commit is contained in:
joeyak 2019-04-13 13:12:08 -04:00
parent 5819bdb85a
commit ad2579d59a
6 changed files with 105 additions and 46 deletions

View File

@ -76,7 +76,7 @@ func (cr *ChatRoom) JoinTemp(conn *chatConnection) (string, error) {
//registering a new client
//returns pointer to a Client, or Nil, if the name is already taken
func (cr *ChatRoom) Join(name, uid string) (*Client, error) {
func (cr *ChatRoom) Join(uid string, data common.JoinData) (*Client, error) {
defer cr.clientsMtx.Unlock()
cr.clientsMtx.Lock()
@ -85,41 +85,63 @@ func (cr *ChatRoom) Join(name, uid string) (*Client, error) {
return nil, errors.New("connection is missing from temp connections")
}
if !common.IsValidName(name) {
return nil, UserFormatError{Name: name}
}
nameLower := strings.ToLower(name)
for _, client := range cr.clients {
if strings.ToLower(client.name) == nameLower {
return nil, UserTakenError{Name: name}
sendHiddenMessage := func(cd common.ClientDataType, i interface{}) {
// If the message cant be converted, then just don't send
if d, err := common.NewChatHiddenMessage(cd, i).ToJSON(); err == nil {
conn.WriteJSON(d)
}
}
client, err := NewClient(conn, cr, name, common.RandomColor())
if !common.IsValidName(data.Name) {
sendHiddenMessage(common.CdNotify, "Invalid name")
return nil, UserFormatError{Name: data.Name}
}
nameLower := strings.ToLower(data.Name)
for _, client := range cr.clients {
if strings.ToLower(client.name) == nameLower {
sendHiddenMessage(common.CdNotify, "Name already taken")
return nil, UserTakenError{Name: data.Name}
}
}
// If color is invalid, then set it to a random color
if !common.IsValidColor(data.Color) {
data.Color = common.RandomColor()
}
client, err := NewClient(conn, cr, data.Name, data.Color)
if err != nil {
sendHiddenMessage(common.CdNotify, "Could not join client")
return nil, fmt.Errorf("Unable to join client: %v", err)
}
// Overwrite to use client instead
sendHiddenMessage = func(cd common.ClientDataType, i interface{}) {
client.SendChatData(common.NewChatHiddenMessage(cd, i))
}
host := client.Host()
if banned, names := settings.IsBanned(host); banned {
return nil, newBannedUserError(host, name, names)
sendHiddenMessage(common.CdNotify, "You are banned")
return nil, newBannedUserError(host, data.Name, names)
}
cr.clients[uid] = client
delete(cr.tempConn, uid)
common.LogChatf("[join] %s %s\n", host, name)
common.LogChatf("[join] %s %s\n", host, data.Color)
playingCommand, err := common.NewChatCommand(common.CmdPlaying, []string{cr.playing, cr.playingLink}).ToJSON()
if err != nil {
common.LogErrorf("Unable to encode playing command on join: %s\n", err)
} else {
client.Send(playingCommand)
}
cr.AddEventMsg(common.EvJoin, name, client.color)
cr.AddEventMsg(common.EvJoin, data.Name, data.Color)
client.SendChatData(common.NewChatHiddenMessage(common.CdEmote, common.Emotes))
sendHiddenMessage(common.CdJoin, nil)
sendHiddenMessage(common.CdEmote, common.Emotes)
return client, nil
}

View File

@ -242,3 +242,8 @@ func DecodeData(rawjson string) (ChatDataJSON, error) {
err := json.Unmarshal([]byte(rawjson), &data)
return data, err
}
type JoinData struct {
Name string
Color string
}

View File

@ -10,6 +10,8 @@ const (
CdAuth // get the auth levels of the user
CdColor // get the users color
CdEmote // get a list of emotes
CdJoin // a message saying the client wants to join
CdNotify // a notify message for the client to show
)
type DataType int

View File

@ -1,6 +1,7 @@
package main
import (
"encoding/json"
"fmt"
"html/template"
"io"
@ -119,12 +120,20 @@ func wsHandler(w http.ResponseWriter, r *http.Request) {
var data common.ClientData
err := chatConn.ReadData(&data)
if err != nil {
common.LogInfof("[handler] Client closed connection: %s\n", conn.RemoteAddr().String())
common.LogInfof("[handler] Client closed connection: %s: %v\n",
conn.RemoteAddr().String(), err)
conn.Close()
return
}
client, err = chat.Join(data.Message, uid)
var joinData common.JoinData
err = json.Unmarshal([]byte(data.Message), &joinData)
if err != nil {
common.LogInfof("[handler] Could not unmarshal join data %#v: %v\n", data.Message, err)
continue
}
client, err = chat.Join(uid, joinData)
if err != nil {
switch err.(type) {
case UserFormatError, UserTakenError:

View File

@ -16,6 +16,10 @@ function getCookie(cname) {
return "";
}
function deleteCookie(cname) {
document.cookie = `${cname}=;expires=Thu, 01 Jan 1970 00:00:01 GMT`
}
function setPlaying(title, link) {
if (title !== "") {
$('#playing').text(title);
@ -96,28 +100,6 @@ function closeChat() {
inChat = false;
}
function join() {
let name = $("#name").val();
if (!isValidName(name)) {
setNotifyBox("Please input a valid name");
return;
}
if (!sendMessage($("#name").val())) {
setNotifyBox("could not join");
return;
}
setNotifyBox();
openChat();
let color = getCookie("color");
if (color !== "") {
// Do a timeout because timings
setTimeout(() => {
sendMessage("/color " + color);
}, 250);
}
}
function websocketSend(data) {
if (ws.readyState == ws.OPEN) {
ws.send(data);

View File

@ -19,6 +19,41 @@ var (
auth common.CommandLevel
)
func getElement(s string) js.Value {
return js.Get("document").Call("getElementById", s)
}
func join(v []js.Value) {
color := js.Call("getCookie", "color").String()
if color == "" {
// If a color is not set, do a random color
color = common.RandomColor()
} else if !common.IsValidColor(color) {
// Don't show the user the error, just clear the cookie
common.LogInfof("%#v is not a valid color, clearing cookie", color)
js.Call("deleteCookie", "color")
}
joinData, err := json.Marshal(common.JoinData{
Name: getElement("name").Get("value").String(),
Color: color,
})
if err != nil {
notify("Error prepping data for join")
common.LogErrorf("Could not prep data: %#v\n", err)
}
data, err := json.Marshal(common.ClientData{
Type: common.CdJoin,
Message: string(joinData),
})
if err != nil {
common.LogErrorf("Could not marshal data: %v", err)
}
js.Call("websocketSend", string(data))
}
func recieve(v []js.Value) {
if len(v) == 0 {
fmt.Println("No data received")
@ -61,6 +96,11 @@ func recieve(v []js.Value) {
emotes[k] = v.(string)
}
sort.Strings(emoteNames)
case common.CdJoin:
notify("")
js.Call("openChat")
case common.CdNotify:
notify(h.Data.(string))
}
case common.DTEvent:
d := chat.Data.(common.DataEvent)
@ -152,6 +192,10 @@ func showChatError(err error) {
}
}
func notify(msg string) {
js.Call("setNotifyBox", msg)
}
func showTimestamp(v []js.Value) {
if len(v) != 1 {
// Don't bother with returning a value
@ -167,13 +211,6 @@ func isValidColor(this js.Value, v []js.Value) interface{} {
return common.IsValidColor(v[0].String())
}
func isValidName(this js.Value, v []js.Value) interface{} {
if len(v) != 1 {
return false
}
return common.IsValidName(v[0].String())
}
func debugValues(v []js.Value) {
for k, v := range map[string]interface{}{
"timestamp": timestamp,
@ -190,15 +227,17 @@ func debugValues(v []js.Value) {
}
func main() {
common.SetupLogging(common.LLDebug, "")
js.Set("processMessageKey", js.FuncOf(processMessageKey))
js.Set("sendMessage", js.FuncOf(send))
js.Set("isValidColor", js.FuncOf(isValidColor))
js.Set("isValidName", js.FuncOf(isValidName))
js.Set("recieveMessage", js.CallbackOf(recieve))
js.Set("processMessage", js.CallbackOf(processMessage))
js.Set("debugValues", js.CallbackOf(debugValues))
js.Set("showTimestamp", js.CallbackOf(showTimestamp))
js.Set("join", js.CallbackOf(join))
go func() {
time.Sleep(time.Second * 1)