security: ensure injected strings are properly escaped
Uses over for JSON compatibility.
This commit is contained in:
+34
-29
@@ -2,6 +2,7 @@ package envelope
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
|
"encoding/json"
|
||||||
"strconv"
|
"strconv"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -19,13 +20,13 @@ func EncloseEvent(event []byte) Envelope {
|
|||||||
// Format: ["OK", eventID, status, message]
|
// Format: ["OK", eventID, status, message]
|
||||||
func EncloseOK(eventID string, status bool, message string) Envelope {
|
func EncloseOK(eventID string, status bool, message string) Envelope {
|
||||||
var buf bytes.Buffer
|
var buf bytes.Buffer
|
||||||
buf.WriteString(`["OK","`)
|
buf.WriteString(`["OK",`)
|
||||||
buf.WriteString(eventID)
|
buf.Write(quote(eventID))
|
||||||
buf.WriteString(`",`)
|
buf.WriteString(`,`)
|
||||||
buf.WriteString(strconv.FormatBool(status))
|
buf.WriteString(strconv.FormatBool(status))
|
||||||
buf.WriteString(`,"`)
|
buf.WriteString(`,`)
|
||||||
buf.WriteString(message)
|
buf.Write(quote(message))
|
||||||
buf.WriteString(`"]`)
|
buf.WriteString(`]`)
|
||||||
return buf.Bytes()
|
return buf.Bytes()
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -33,9 +34,8 @@ func EncloseOK(eventID string, status bool, message string) Envelope {
|
|||||||
// Format: ["REQ", subID, filter1, filter2, ...]
|
// Format: ["REQ", subID, filter1, filter2, ...]
|
||||||
func EncloseReq(subID string, filters [][]byte) Envelope {
|
func EncloseReq(subID string, filters [][]byte) Envelope {
|
||||||
var buf bytes.Buffer
|
var buf bytes.Buffer
|
||||||
buf.WriteString(`["REQ","`)
|
buf.WriteString(`["REQ",`)
|
||||||
buf.WriteString(subID)
|
buf.Write(quote(subID))
|
||||||
buf.WriteString(`"`)
|
|
||||||
|
|
||||||
for _, filter := range filters {
|
for _, filter := range filters {
|
||||||
buf.WriteString(`,`)
|
buf.WriteString(`,`)
|
||||||
@@ -50,9 +50,9 @@ func EncloseReq(subID string, filters [][]byte) Envelope {
|
|||||||
// Format: ["EVENT", subID, event]
|
// Format: ["EVENT", subID, event]
|
||||||
func EncloseSubscriptionEvent(subID string, event []byte) Envelope {
|
func EncloseSubscriptionEvent(subID string, event []byte) Envelope {
|
||||||
var buf bytes.Buffer
|
var buf bytes.Buffer
|
||||||
buf.WriteString(`["EVENT","`)
|
buf.WriteString(`["EVENT",`)
|
||||||
buf.WriteString(subID)
|
buf.Write(quote(subID))
|
||||||
buf.WriteString(`",`)
|
buf.WriteString(`,`)
|
||||||
buf.Write(event)
|
buf.Write(event)
|
||||||
buf.WriteByte(']')
|
buf.WriteByte(']')
|
||||||
return buf.Bytes()
|
return buf.Bytes()
|
||||||
@@ -62,9 +62,9 @@ func EncloseSubscriptionEvent(subID string, event []byte) Envelope {
|
|||||||
// Format: ["EOSE", subID]
|
// Format: ["EOSE", subID]
|
||||||
func EncloseEOSE(subID string) Envelope {
|
func EncloseEOSE(subID string) Envelope {
|
||||||
var buf bytes.Buffer
|
var buf bytes.Buffer
|
||||||
buf.WriteString(`["EOSE","`)
|
buf.WriteString(`["EOSE",`)
|
||||||
buf.WriteString(subID)
|
buf.Write(quote(subID))
|
||||||
buf.WriteString(`"]`)
|
buf.WriteString(`]`)
|
||||||
return buf.Bytes()
|
return buf.Bytes()
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -72,9 +72,9 @@ func EncloseEOSE(subID string) Envelope {
|
|||||||
// Format: ["CLOSE", subID]
|
// Format: ["CLOSE", subID]
|
||||||
func EncloseClose(subID string) Envelope {
|
func EncloseClose(subID string) Envelope {
|
||||||
var buf bytes.Buffer
|
var buf bytes.Buffer
|
||||||
buf.WriteString(`["CLOSE","`)
|
buf.WriteString(`["CLOSE",`)
|
||||||
buf.WriteString(subID)
|
buf.Write(quote(subID))
|
||||||
buf.WriteString(`"]`)
|
buf.WriteString(`]`)
|
||||||
return buf.Bytes()
|
return buf.Bytes()
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -82,11 +82,11 @@ func EncloseClose(subID string) Envelope {
|
|||||||
// Format: ["CLOSED", subID, message]
|
// Format: ["CLOSED", subID, message]
|
||||||
func EncloseClosed(subID string, message string) Envelope {
|
func EncloseClosed(subID string, message string) Envelope {
|
||||||
var buf bytes.Buffer
|
var buf bytes.Buffer
|
||||||
buf.WriteString(`["CLOSED","`)
|
buf.WriteString(`["CLOSED",`)
|
||||||
buf.WriteString(subID)
|
buf.Write(quote(subID))
|
||||||
buf.WriteString(`","`)
|
buf.WriteString(`,`)
|
||||||
buf.WriteString(message)
|
buf.Write(quote(message))
|
||||||
buf.WriteString(`"]`)
|
buf.WriteString(`]`)
|
||||||
return buf.Bytes()
|
return buf.Bytes()
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -94,9 +94,9 @@ func EncloseClosed(subID string, message string) Envelope {
|
|||||||
// Format: ["NOTICE", message]
|
// Format: ["NOTICE", message]
|
||||||
func EncloseNotice(message string) Envelope {
|
func EncloseNotice(message string) Envelope {
|
||||||
var buf bytes.Buffer
|
var buf bytes.Buffer
|
||||||
buf.WriteString(`["NOTICE","`)
|
buf.WriteString(`["NOTICE",`)
|
||||||
buf.WriteString(message)
|
buf.Write(quote(message))
|
||||||
buf.WriteString(`"]`)
|
buf.WriteString(`]`)
|
||||||
return buf.Bytes()
|
return buf.Bytes()
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -104,9 +104,9 @@ func EncloseNotice(message string) Envelope {
|
|||||||
// Format: ["AUTH", challenge]
|
// Format: ["AUTH", challenge]
|
||||||
func EncloseAuthChallenge(challenge string) Envelope {
|
func EncloseAuthChallenge(challenge string) Envelope {
|
||||||
var buf bytes.Buffer
|
var buf bytes.Buffer
|
||||||
buf.WriteString(`["AUTH","`)
|
buf.WriteString(`["AUTH",`)
|
||||||
buf.WriteString(challenge)
|
buf.Write(quote(challenge))
|
||||||
buf.WriteString(`"]`)
|
buf.WriteString(`]`)
|
||||||
return buf.Bytes()
|
return buf.Bytes()
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -119,3 +119,8 @@ func EncloseAuthResponse(event []byte) Envelope {
|
|||||||
buf.WriteByte(']')
|
buf.WriteByte(']')
|
||||||
return buf.Bytes()
|
return buf.Bytes()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func quote(s string) []byte {
|
||||||
|
q, _ := json.Marshal(s)
|
||||||
|
return q
|
||||||
|
}
|
||||||
|
|||||||
@@ -50,6 +50,13 @@ func TestEncloseOK(t *testing.T) {
|
|||||||
message: "Event accepted",
|
message: "Event accepted",
|
||||||
want: []byte(`["OK","abc123",true,"Event accepted"]`),
|
want: []byte(`["OK","abc123",true,"Event accepted"]`),
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
name: "escapes quotes",
|
||||||
|
eventID: `"abc123"`,
|
||||||
|
status: true,
|
||||||
|
message: `"Event accepted"`,
|
||||||
|
want: []byte(`["OK","\"abc123\"",true,"\"Event accepted\""]`),
|
||||||
|
},
|
||||||
{
|
{
|
||||||
name: "rejected event",
|
name: "rejected event",
|
||||||
eventID: "xyz789",
|
eventID: "xyz789",
|
||||||
@@ -98,6 +105,12 @@ func TestEncloseReq(t *testing.T) {
|
|||||||
filters: [][]byte{},
|
filters: [][]byte{},
|
||||||
want: []byte(`["REQ","sub3"]`),
|
want: []byte(`["REQ","sub3"]`),
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
name: "escapes quotes",
|
||||||
|
subID: `"sub3"`,
|
||||||
|
filters: [][]byte{},
|
||||||
|
want: []byte(`["REQ","\"sub3\""]`),
|
||||||
|
},
|
||||||
}
|
}
|
||||||
for _, tc := range cases {
|
for _, tc := range cases {
|
||||||
t.Run(tc.name, func(t *testing.T) {
|
t.Run(tc.name, func(t *testing.T) {
|
||||||
@@ -126,6 +139,12 @@ func TestEncloseSubscriptionEvent(t *testing.T) {
|
|||||||
event: []byte(`{}`),
|
event: []byte(`{}`),
|
||||||
want: []byte(`["EVENT","sub2",{}]`),
|
want: []byte(`["EVENT","sub2",{}]`),
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
name: "escapes quotes",
|
||||||
|
subID: `"sub2"`,
|
||||||
|
event: []byte(`{}`),
|
||||||
|
want: []byte(`["EVENT","\"sub2\"",{}]`),
|
||||||
|
},
|
||||||
}
|
}
|
||||||
for _, tc := range cases {
|
for _, tc := range cases {
|
||||||
t.Run(tc.name, func(t *testing.T) {
|
t.Run(tc.name, func(t *testing.T) {
|
||||||
@@ -146,6 +165,11 @@ func TestEncloseEOSE(t *testing.T) {
|
|||||||
subID: "sub1",
|
subID: "sub1",
|
||||||
want: []byte(`["EOSE","sub1"]`),
|
want: []byte(`["EOSE","sub1"]`),
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
name: "escapes quotes",
|
||||||
|
subID: `"sub1"`,
|
||||||
|
want: []byte(`["EOSE","\"sub1\""]`),
|
||||||
|
},
|
||||||
{
|
{
|
||||||
name: "empty subscription ID",
|
name: "empty subscription ID",
|
||||||
subID: "",
|
subID: "",
|
||||||
@@ -171,6 +195,11 @@ func TestEncloseClose(t *testing.T) {
|
|||||||
subID: "sub1",
|
subID: "sub1",
|
||||||
want: []byte(`["CLOSE","sub1"]`),
|
want: []byte(`["CLOSE","sub1"]`),
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
name: "escapes quotes",
|
||||||
|
subID: `"sub1"`,
|
||||||
|
want: []byte(`["CLOSE","\"sub1\""]`),
|
||||||
|
},
|
||||||
{
|
{
|
||||||
name: "empty subscription ID",
|
name: "empty subscription ID",
|
||||||
subID: "",
|
subID: "",
|
||||||
@@ -198,6 +227,12 @@ func TestEncloseClosed(t *testing.T) {
|
|||||||
message: "Subscription complete",
|
message: "Subscription complete",
|
||||||
want: []byte(`["CLOSED","sub1","Subscription complete"]`),
|
want: []byte(`["CLOSED","sub1","Subscription complete"]`),
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
name: "escapes quotes",
|
||||||
|
subID: `"sub1"`,
|
||||||
|
message: `"Subscription complete"`,
|
||||||
|
want: []byte(`["CLOSED","\"sub1\"","\"Subscription complete\""]`),
|
||||||
|
},
|
||||||
{
|
{
|
||||||
name: "empty message",
|
name: "empty message",
|
||||||
subID: "sub2",
|
subID: "sub2",
|
||||||
@@ -224,6 +259,11 @@ func TestEncloseNotice(t *testing.T) {
|
|||||||
message: "This is a notice",
|
message: "This is a notice",
|
||||||
want: []byte(`["NOTICE","This is a notice"]`),
|
want: []byte(`["NOTICE","This is a notice"]`),
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
name: "escapes quotes",
|
||||||
|
message: `"This is a notice"`,
|
||||||
|
want: []byte(`["NOTICE","\"This is a notice\""]`),
|
||||||
|
},
|
||||||
{
|
{
|
||||||
name: "empty message",
|
name: "empty message",
|
||||||
message: "",
|
message: "",
|
||||||
@@ -249,6 +289,11 @@ func TestEncloseAuthChallenge(t *testing.T) {
|
|||||||
challenge: "random-challenge-string",
|
challenge: "random-challenge-string",
|
||||||
want: []byte(`["AUTH","random-challenge-string"]`),
|
want: []byte(`["AUTH","random-challenge-string"]`),
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
name: "escapes quotes",
|
||||||
|
challenge: `"random-challenge-string"`,
|
||||||
|
want: []byte(`["AUTH","\"random-challenge-string\""]`),
|
||||||
|
},
|
||||||
{
|
{
|
||||||
name: "empty challenge",
|
name: "empty challenge",
|
||||||
challenge: "",
|
challenge: "",
|
||||||
|
|||||||
Reference in New Issue
Block a user