Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse files

HTML is safely escaped in CMsgMsg messages

Also includes a refactor of a good portion of message handling code. The
message server and location server both take the same approach to
processing messages. This has revealed striking symmetries between the
two servers which must be dealt with in the future.
  • Loading branch information...
commit 5fd32ffc0cdc8db963393d05fd81d5f94aaedb32 1 parent 00ef141
Francis Stephens authored
10 exec/example/example.go
View
@@ -3,15 +3,15 @@ package main
import (
"code.google.com/p/go.net/websocket"
"encoding/json"
- "location_server/locserver"
- "location_server/msgserver"
+ "flag"
+ "fmt"
"github.com/fmstephe/simpleid"
+ "location_server/locserver"
"location_server/logutil"
+ "location_server/msgserver"
"location_server/msgutil/msgdef"
"net/http"
"os"
- "flag"
- "fmt"
)
var port = flag.Int("port", 80, "Sets the port the server will attach to")
@@ -22,7 +22,7 @@ var idMaker = simpleid.NewIdMaker()
func idProvider(w http.ResponseWriter, r *http.Request) {
id := idMaker.NewId()
idMsg := msgdef.SIdMsg{Op: msgdef.SIdOp, Id: id}
- if buf, err := json.MarshalForHTML(idMsg); err != nil {
+ if buf, err := json.Marshal(idMsg); err != nil {
println(err.Error())
} else {
w.Write(buf)
54 locserver/connmanager.go
View
@@ -2,22 +2,22 @@ package locserver
import (
"code.google.com/p/go.net/websocket"
- "encoding/json"
"errors"
"github.com/fmstephe/simpleid"
"location_server/logutil"
+ "location_server/msgutil/jsonutil"
"location_server/msgutil/msgdef"
"location_server/user"
)
var iOpErr = errors.New("Illegal Message Op. Operation unrecognised or provided in illegal order.")
-var idSet = simpleid.NewIdMap()
+var idMap = simpleid.NewIdMap()
// Represents a task for the tree manager.
type task struct {
tId uint // The transaction id for this task
op msgdef.ClientOp // The operation to perform for this task
- usr *user.U // The state of the user for this task
+ usr *user.U // The state of the user for this task
}
// Safely creates a new task struct, in particular duplicating usr
@@ -27,7 +27,7 @@ func newTask(tId uint, op msgdef.ClientOp, usr *user.U) *task {
// This is the websocket connection handling function
// The following messages are required in this order
-// 1: User registration message (user id added to idSet)
+// 1: User registration message (user id added to idMap)
// 2: Initial location message
// 3: Move message
//
@@ -37,27 +37,22 @@ func newTask(tId uint, op msgdef.ClientOp, usr *user.U) *task {
// Any error will result in these actions
// 1: The user will be sent a server-error message
// 2: The connection will be closed
-// 3: The user id will be removed from the idSet
+// 3: The user id will be removed from the idMap
// 4: The user will be removed from the treemanager
func HandleLocationService(ws *websocket.Conn) {
var tId uint
usr := user.New(ws)
idMsg := &msgdef.CIdMsg{}
- procReg := processReg(idMsg, usr)
- if err := unmarshalAndProcess(tId, usr.Id, ws, idMsg, procReg); err != nil {
+ procReg := processReg(tId, idMsg, usr)
+ if err := jsonutil.UnmarshalAndProcess(tId, usr.Id, ws, idMsg, procReg); err != nil {
usr.MsgWriter.ErrorAndClose(tId, usr.Id, err.Error())
return
}
- if err := idSet.Add(usr.Id, usr); err != nil {
- usr.MsgWriter.ErrorAndClose(tId, usr.Id, err.Error())
- return
- }
- logutil.Registered(tId, usr.Id)
defer removeId(&tId, usr)
tId++
initLocMsg := msgdef.EmptyCLocMsg()
procInit := processInitLoc(tId, initLocMsg, usr)
- if err := unmarshalAndProcess(tId, usr.Id, ws, initLocMsg, procInit); err != nil {
+ if err := jsonutil.UnmarshalAndProcess(tId, usr.Id, ws, initLocMsg, procInit); err != nil {
usr.MsgWriter.ErrorAndClose(tId, usr.Id, err.Error())
return
}
@@ -66,33 +61,18 @@ func HandleLocationService(ws *websocket.Conn) {
tId++
locMsg := msgdef.EmptyCLocMsg()
procReq := processMove(tId, locMsg, usr)
- if err := unmarshalAndProcess(tId, usr.Id, ws, locMsg, procReq); err != nil {
+ if err := jsonutil.UnmarshalAndProcess(tId, usr.Id, ws, locMsg, procReq); err != nil {
usr.MsgWriter.ErrorAndClose(tId, usr.Id, err.Error())
return
}
}
}
-// Unmarshals a message as a string from the websocket connection
-// Unmarshals that string into msg
-// Calls processFunc provided for arbitrary handling
-func unmarshalAndProcess(tId uint, uId string, ws *websocket.Conn, msg interface{}, processFunc func() error) error {
- var data string
- if err := websocket.Message.Receive(ws, &data); err != nil {
- return err
- }
- logutil.Log(tId, uId, data)
- if err := json.Unmarshal([]byte(data), msg); err != nil {
- return err
- }
- return processFunc()
-}
-
-// Removes this user's id from idSet and logs the action
+// Removes this user's id from idMap and logs the action
func removeId(tId *uint, usr *user.U) {
(*tId)++
logutil.Deregistered(*tId, usr.Id)
- idSet.Remove(usr.Id)
+ idMap.Remove(usr.Id)
}
// Sends a remove message to the tree manager
@@ -104,15 +84,19 @@ func removeFromTree(tId *uint, usr *user.U) {
// Handle registration message
// Success will leave usr with initialised Id field
-func processReg(idMsg *msgdef.CIdMsg, usr *user.U) func() error {
+func processReg(tId uint, idMsg *msgdef.CIdMsg, usr *user.U) func() error {
return func() error {
+ if idMsg.Op != msgdef.CAddOp {
+ return errors.New("Incorrect op-code for id registration: " + string(idMsg.Op))
+ }
if err := idMsg.Validate(); err != nil {
return err
}
- if idMsg.Op != msgdef.CAddOp {
- return iOpErr
- }
usr.Id = idMsg.Id
+ if err := idMap.Add(usr.Id, usr); err != nil {
+ return err
+ }
+ logutil.Registered(tId, usr.Id)
return nil
}
}
55 msgserver/msgserver.go
View
@@ -17,35 +17,52 @@ func HandleMessageService(ws *websocket.Conn) {
var tId uint
usr := user.New(ws)
idMsg := &msgdef.CIdMsg{}
- if err := jsonutil.JSONCodec.Receive(ws, idMsg); err != nil {
+ procReg := processReg(tId, idMsg, usr)
+ if err := jsonutil.UnmarshalAndProcess(tId, usr.Id, ws, idMsg, procReg); err != nil {
usr.MsgWriter.ErrorAndClose(tId, usr.Id, err.Error())
return
}
- if err := idMsg.Validate(); err != nil {
- usr.MsgWriter.ErrorAndClose(tId, usr.Id, err.Error())
- return
- }
- processReg(idMsg, usr)
- if err := idMap.Add(usr.Id, usr); err != nil {
- usr.MsgWriter.ErrorAndClose(tId, usr.Id, err.Error())
- return
- }
- logutil.Registered(tId, usr.Id)
defer removeUser(&tId, usr.Id)
for {
tId++
msg := &msgdef.CMsgMsg{}
- if err := jsonutil.JSONCodec.Receive(ws, msg); err != nil {
+ procMsg := processMsg(tId, msg, usr)
+ if err := jsonutil.UnmarshalAndProcess(tId, usr.Id, ws, msg, procMsg); err != nil {
usr.MsgWriter.ErrorAndClose(tId, usr.Id, err.Error())
return
}
+ }
+}
+
+func processReg(tId uint, idMsg *msgdef.CIdMsg, usr *user.U) func() error {
+ return func() error {
+ if idMsg.Op != msgdef.CAddOp {
+ return errors.New("Incorrect op-code for id registration: " + string(idMsg.Op))
+ }
+ if err := idMsg.Validate(); err != nil {
+ return err
+ }
+ usr.Id = idMsg.Id
+ if err := idMap.Add(usr.Id, usr); err != nil {
+ return err
+ }
+ logutil.Registered(tId, usr.Id)
+ return nil
+ }
+}
+
+func processMsg(tId uint, msg *msgdef.CMsgMsg, usr *user.U) func() error {
+ return func() error {
+ if msg.Op != msgdef.CMsgOp {
+ return errors.New("Incorrect op-code for msg: " + string(msg.Op))
+ }
if err := msg.Validate(); err != nil {
- usr.MsgWriter.ErrorAndClose(tId, usr.Id, err.Error())
- return
+ return err
}
if idMap.Contains(msg.To) {
forUser := idMap.Get(msg.To).(*user.U)
- msgMsg := &msgdef.SMsgMsg{Op: msgdef.SMsgOp, From: usr.Id, Content: msg.Content}
+ safeContent := jsonutil.SanitiseJSON(msg.Content)
+ msgMsg := &msgdef.SMsgMsg{Op: msgdef.SMsgOp, From: usr.Id, Content: safeContent}
sMsg := &msgdef.ServerMsg{Msg: msgMsg, TId: tId, UId: usr.Id}
forUser.MsgWriter.WriteMsg(sMsg)
logutil.Log(tId, usr.Id, fmt.Sprintf("Content: '%s' sent to: '%s'", msg.Content, msg.To))
@@ -54,16 +71,8 @@ func HandleMessageService(ws *websocket.Conn) {
sMsg := &msgdef.ServerMsg{Msg: nuMsg, TId: tId, UId: usr.Id}
usr.MsgWriter.WriteMsg(sMsg)
}
- }
-}
-
-func processReg(idMsg *msgdef.CIdMsg, usr *user.U) error {
- switch idMsg.Op {
- case msgdef.CAddOp:
- usr.Id = idMsg.Id
return nil
}
- return errors.New("Incorrect op-code for id registration: " + string(idMsg.Op))
}
func removeUser(tId *uint, uId string) {
48 msgutil/jsonutil/jsonutil.go
View
@@ -3,15 +3,51 @@ package jsonutil
import (
"code.google.com/p/go.net/websocket"
"encoding/json"
+ "html"
+ "location_server/logutil"
)
-func jsonMarshal(v interface{}) (msg []byte, payloadType byte, err error) {
- msg, err = json.MarshalForHTML(v)
- return msg, websocket.TextFrame, err
+// Unmarshals a websocket message into msgi as JSON.
+func UnmarshalAndLog(tId uint, uId string, ws *websocket.Conn, msg interface{}) error {
+ var data string
+ if err := websocket.Message.Receive(ws, &data); err != nil {
+ return err
+ }
+ logutil.Log(tId, uId, data)
+ if err := json.Unmarshal([]byte(data), msg); err != nil {
+ return err
+ }
+ return nil
}
-func jsonUnmarshal(msg []byte, payloadType byte, v interface{}) (err error) {
- return json.Unmarshal(msg, v)
+func UnmarshalAndProcess(tId uint, uId string, ws *websocket.Conn, msg interface{}, processFunc func() error) error {
+ UnmarshalAndLog(tId, uId, ws, msg)
+ return processFunc()
}
-var JSONCodec = websocket.Codec{jsonMarshal, jsonUnmarshal}
+//
+func SanitiseJSON(v interface{}) interface{} {
+ if v == nil {
+ return nil
+ }
+ if s, ok := v.(string); ok {
+ return html.EscapeString(s)
+ }
+ sanitiseJSON(v)
+ return v
+}
+
+func sanitiseJSON(parent interface{}) {
+ switch parent.(type) {
+ case map[string]interface{}:
+ parentMap := parent.(map[string]interface{})
+ for k, child := range parentMap {
+ switch child.(type) {
+ case string:
+ parentMap[k] = html.EscapeString(child.(string))
+ case map[string]interface{}:
+ SanitiseJSON(child)
+ }
+ }
+ }
+}
12 msgutil/msgdef/msgmsg.go
View
@@ -8,9 +8,9 @@ import (
const CMsgOp = ClientOp("cMsg")
type CMsgMsg struct {
- Op ClientOp `json:"op"`
- To string `json:"to"`
- Content interface{} `json:"content"`
+ Op ClientOp `json:"op"`
+ To string `json:"to"`
+ Content interface{} `json:"content"`
}
func (msg *CMsgMsg) Validate() error {
@@ -30,9 +30,9 @@ func (msg *CMsgMsg) Validate() error {
const SMsgOp = ServerOp("sMsg")
type SMsgMsg struct {
- Op ServerOp `json:"op"`
- From string `json:"from"`
- Content interface{} `json:"content"`
+ Op ServerOp `json:"op"`
+ From string `json:"from"`
+ Content interface{} `json:"content"`
}
// Indicates that UserId is not registered on the msg_server
2  user/user.go
View
@@ -1,8 +1,8 @@
package user
import (
- "location_server/msgutil/msgwriter"
"code.google.com/p/go.net/websocket"
+ "location_server/msgutil/msgwriter"
)
// Identifies a user identifed with a lat/lng location currently registered with this service
Please sign in to comment.
Something went wrong with that request. Please try again.