Redo protocol for proxy--broker messages

Switch to containing all communication between the proxy and the broker
in the HTTP response body. This will make things easier if we ever use
something other than HTTP communicate between different actors in the
snowflake system.

Other changes to the protocol are as follows:
- requests are accompanied by a version number so the broker can be
backwards compatable if desired in the future
- all responses are 200 OK unless the request was badly formatted
This commit is contained in:
Cecylia Bocovich 2019-10-07 14:02:01 -04:00
parent abefae1587
commit c4ae64905b
6 changed files with 489 additions and 53 deletions

214
common/messages/proxy.go Normal file
View file

@ -0,0 +1,214 @@
//Package for communication with the snowflake broker
//import "git.torproject.org/pluggable-transports/snowflake.git/common/messages"
package messages
import (
"encoding/json"
"fmt"
)
const version = "1.0"
/* Version 1.0 specification:
== ProxyPollRequest ==
{
Sid: [generated session id of proxy]
Version: 1.0
}
== ProxyPollResponse ==
1) If a client is matched:
HTTP 200 OK
{
Status: "client match",
{
type: offer,
sdp: [WebRTC SDP]
}
}
2) If a client is not matched:
HTTP 200 OK
{
Status: "no proxies"
}
3) If the request is malformed:
HTTP 400 BadRequest
== ProxyAnswerRequest ==
{
Sid: [generated session id of proxy]
Version: 1.0
Answer:
{
type: answer
sdp: [WebRTC SDP]
}
}
== ProxyAnswerResponse ==
1) If the client retrieved the answer:
HTTP 200 OK
{
Status: "success"
}
2) If the client left:
HTTP 200 OK
{
Status: "client gone"
}
3) If the request is malformed:
HTTP 400 BadRequest
*/
type ProxyPollRequest struct {
Sid string
Version string
}
func EncodePollRequest(sid string) ([]byte, error) {
return json.Marshal(ProxyPollRequest{
Sid: sid,
Version: version,
})
}
// Decodes a poll message from a snowflake proxy and returns the
// sid of the proxy on success and an error if it failed
func DecodePollRequest(data []byte) (string, error) {
var message ProxyPollRequest
err := json.Unmarshal(data, &message)
if err != nil {
return "", err
}
if message.Version != "1.0" {
return "", fmt.Errorf("using unknown version")
}
// Version 1.0 requires an Sid
if message.Sid == "" {
return "", fmt.Errorf("no supplied session id")
}
return message.Sid, nil
}
type ProxyPollResponse struct {
Status string
Offer string
}
func EncodePollResponse(offer string, success bool) ([]byte, error) {
if success {
return json.Marshal(ProxyPollResponse{
Status: "client match",
Offer: offer,
})
}
return json.Marshal(ProxyPollResponse{
Status: "no match",
})
}
// Decodes a poll response from the broker and returns an offer
// If there is a client match, the returned offer string will be non-empty
func DecodePollResponse(data []byte) (string, error) {
var message ProxyPollResponse
err := json.Unmarshal(data, &message)
if err != nil {
return "", err
}
if message.Status == "" {
return "", fmt.Errorf("received invalid data")
}
if message.Status == "client match" {
if message.Offer == "" {
return "", fmt.Errorf("no supplied offer")
}
} else {
message.Offer = ""
}
return message.Offer, nil
}
type ProxyAnswerRequest struct {
Version string
Sid string
Answer string
}
func EncodeAnswerRequest(answer string, sid string) ([]byte, error) {
return json.Marshal(ProxyAnswerRequest{
Version: "1.0",
Sid: sid,
Answer: answer,
})
}
// Returns the sdp answer and proxy sid
func DecodeAnswerRequest(data []byte) (string, string, error) {
var message ProxyAnswerRequest
err := json.Unmarshal(data, &message)
if err != nil {
return "", "", err
}
if message.Version != "1.0" {
return "", "", fmt.Errorf("using unknown version")
}
if message.Sid == "" || message.Answer == "" {
return "", "", fmt.Errorf("no supplied sid or answer")
}
return message.Answer, message.Sid, nil
}
type ProxyAnswerResponse struct {
Status string
}
func EncodeAnswerResponse(success bool) ([]byte, error) {
if success {
return json.Marshal(ProxyAnswerResponse{
Status: "success",
})
}
return json.Marshal(ProxyAnswerResponse{
Status: "client gone",
})
}
func DecodeAnswerResponse(data []byte) (bool, error) {
var message ProxyAnswerResponse
var success bool
err := json.Unmarshal(data, &message)
if err != nil {
return success, err
}
if message.Status == "" {
return success, fmt.Errorf("received invalid data")
}
if message.Status == "success" {
success = true
}
return success, nil
}