0
0
Fork 0
mirror of https://github.com/schollz/croc.git synced 2025-10-11 13:21:00 +02:00

consolidate structures

This commit is contained in:
Zack Scholl 2018-06-28 17:22:58 -07:00
parent 6f1e6f3da8
commit 7a1f0f66cd
2 changed files with 121 additions and 164 deletions

View file

@ -5,6 +5,8 @@ import (
"net" "net"
"sync" "sync"
"time" "time"
"github.com/gorilla/websocket"
) )
const ( const (
@ -24,8 +26,8 @@ type relayState struct {
type channelData struct { type channelData struct {
// Public // Public
// Name is the name of the channel // Channel is the name of the channel
Name string `json:"name,omitempty"` Channel string `json:"channel,omitempty"`
// State contains state variables that are public to both parties // State contains state variables that are public to both parties
State map[string][]byte `json:"state"` State map[string][]byte `json:"state"`
// TransferReady is set by the relaying when both parties have connected // TransferReady is set by the relaying when both parties have connected
@ -43,6 +45,8 @@ type channelData struct {
curve elliptic.Curve curve elliptic.Curve
// connection information is stored when the clients do connect over TCP // connection information is stored when the clients do connect over TCP
connection [2]net.Conn connection [2]net.Conn
// websocket connections
websocketConn [2]*websocket.Conn
// startTime is the time that the channel was opened // startTime is the time that the channel was opened
startTime time.Time startTime time.Time
} }
@ -58,7 +62,9 @@ type response struct {
Message string `json:"message"` Message string `json:"message"`
} }
type payloadOpen struct { type payload struct {
// Open set to true when trying to open
Open bool `json:"open"`
// Channel is used to designate the channel of interest // Channel is used to designate the channel of interest
Channel string `json:"channel"` Channel string `json:"channel"`
// Role designates which role the person will take; // Role designates which role the person will take;
@ -66,13 +72,14 @@ type payloadOpen struct {
Role int `json:"role"` Role int `json:"role"`
// Curve is the curve to be used. // Curve is the curve to be used.
Curve string `json:"curve"` Curve string `json:"curve"`
}
type payloadChannel struct { // Update set to true when updating
Channel string `json:"channel" binding:"required"` Update bool `json:"update"`
UUID string `json:"uuid" binding:"required"` // State is the state information to be updated
State map[string][]byte `json:"state"` State map[string][]byte `json:"state"`
Close bool `json:"close"`
// Close set to true when closing:
Close bool `json:"close"`
} }
func newChannelData(name string) (cd *channelData) { func newChannelData(name string) (cd *channelData) {

View file

@ -13,168 +13,118 @@ import (
) )
func (c *Croc) updateChannel(p payloadChannel) (r response, err error) { func (c *Croc) updateChannel(p payloadChannel) (r response, err error) {
c.rs.Lock()
defer c.rs.Unlock()
r.Success = true
// determine if channel is invalid
if _, ok := c.rs.channel[p.Channel]; !ok {
err = errors.Errorf("channel '%s' does not exist", p.Channel)
return
}
// determine if UUID is invalid for channel
if p.UUID != c.rs.channel[p.Channel].uuids[0] &&
p.UUID != c.rs.channel[p.Channel].uuids[1] {
err = errors.Errorf("uuid '%s' is invalid", p.UUID)
return
}
// check if the action is to close the channel
if p.Close {
delete(c.rs.channel, p.Channel)
r.Message = "deleted " + p.Channel
return
}
// assign each key provided
assignedKeys := []string{}
for key := range p.State {
// TODO:
// add a check that the value of key is not enormous
// add only if it is a valid key
if _, ok := c.rs.channel[p.Channel].State[key]; ok {
assignedKeys = append(assignedKeys, key)
c.rs.channel[p.Channel].State[key] = p.State[key]
}
}
// return the current state
r.Data = c.rs.channel[p.Channel]
r.Message = fmt.Sprintf("assigned %d keys: %v", len(assignedKeys), assignedKeys)
return
}
func (c *Croc) joinChannel(p payloadChannel) (r response, err error) {
c.rs.Lock()
defer c.rs.Unlock()
r.Success = true
// determine if sender or recipient
if p.Role != 0 && p.Role != 1 {
err = errors.Errorf("no such role of %d", p.Role)
return
}
// determine channel
if p.Channel == "" {
// TODO:
// find an empty channel
p.Channel = "chou"
}
if _, ok := c.rs.channel[p.Channel]; ok {
// channel is not empty
if c.rs.channel[p.Channel].uuids[p.Role] != "" {
err = errors.Errorf("channel '%s' already occupied by role %d", p.Channel, p.Role)
return
}
}
r.Channel = p.Channel
if _, ok := c.rs.channel[r.Channel]; !ok {
c.rs.channel[r.Channel] = newChannelData(r.Channel)
}
// assign UUID for the role in the channel
c.rs.channel[r.Channel].uuids[p.Role] = uuid4.New().String()
r.UUID = c.rs.channel[r.Channel].uuids[p.Role]
log.Debugf("(%s) %s has joined as role %d", r.Channel, r.UUID, p.Role)
// if channel is not open, set initial parameters
if !c.rs.channel[r.Channel].isopen {
c.rs.channel[r.Channel].isopen = true
c.rs.channel[r.Channel].Ports = tcpPorts
c.rs.channel[r.Channel].startTime = time.Now()
switch curve := p.Curve; curve {
case "p224":
c.rs.channel[r.Channel].curve = elliptic.P224()
case "p256":
c.rs.channel[r.Channel].curve = elliptic.P256()
case "p384":
c.rs.channel[r.Channel].curve = elliptic.P384()
case "p521":
c.rs.channel[r.Channel].curve = elliptic.P521()
default:
// TODO:
// add SIEC
p.Curve = "p256"
c.rs.channel[r.Channel].curve = elliptic.P256()
}
log.Debugf("(%s) using curve '%s'", r.Channel, p.Curve)
c.rs.channel[r.Channel].State["curve"] = []byte(p.Curve)
}
r.Message = fmt.Sprintf("assigned role %d in channel '%s'", p.Role, r.Channel)
return
} }
func (c *Croc) startServer(tcpPorts []string, port string) (err error) { func (c *Croc) startServer(tcpPorts []string, port string) (err error) {
// start cleanup on dangling channels // start cleanup on dangling channels
go c.channelCleanup() go c.channelCleanup()
// start server // TODO:
gin.SetMode(gin.ReleaseMode) // insert websockets here
r := gin.New()
r.Use(middleWareHandler(), gin.Recovery())
r.POST("/channel", func(cg *gin.Context) {
r, err := func(cg *gin.Context) (r response, err error) {
c.rs.Lock()
defer c.rs.Unlock()
r.Success = true
var p payloadChannel
err = cg.ShouldBindJSON(&p)
if err != nil {
log.Errorf("failed on payload %+v", p)
err = errors.Wrap(err, "problem parsing /channel")
return
}
// determine if channel is invalid
if _, ok := c.rs.channel[p.Channel]; !ok {
err = errors.Errorf("channel '%s' does not exist", p.Channel)
return
}
// determine if UUID is invalid for channel
if p.UUID != c.rs.channel[p.Channel].uuids[0] &&
p.UUID != c.rs.channel[p.Channel].uuids[1] {
err = errors.Errorf("uuid '%s' is invalid", p.UUID)
return
}
// check if the action is to close the channel
if p.Close {
delete(c.rs.channel, p.Channel)
r.Message = "deleted " + p.Channel
return
}
// assign each key provided
assignedKeys := []string{}
for key := range p.State {
// TODO:
// add a check that the value of key is not enormous
// add only if it is a valid key
if _, ok := c.rs.channel[p.Channel].State[key]; ok {
assignedKeys = append(assignedKeys, key)
c.rs.channel[p.Channel].State[key] = p.State[key]
}
}
// return the current state
r.Data = c.rs.channel[p.Channel]
r.Message = fmt.Sprintf("assigned %d keys: %v", len(assignedKeys), assignedKeys)
return
}(cg)
if err != nil {
log.Debugf("bad /channel: %s", err.Error())
r.Message = err.Error()
r.Success = false
}
bR, _ := json.Marshal(r)
cg.Data(200, "application/json", bR)
})
r.POST("/join", func(cg *gin.Context) {
r, err := func(cg *gin.Context) (r response, err error) {
c.rs.Lock()
defer c.rs.Unlock()
r.Success = true
var p payloadOpen
err = cg.ShouldBindJSON(&p)
if err != nil {
log.Errorf("failed on payload %+v", p)
err = errors.Wrap(err, "problem parsing")
return
}
// determine if sender or recipient
if p.Role != 0 && p.Role != 1 {
err = errors.Errorf("no such role of %d", p.Role)
return
}
// determine channel
if p.Channel == "" {
// TODO:
// find an empty channel
p.Channel = "chou"
}
if _, ok := c.rs.channel[p.Channel]; ok {
// channel is not empty
if c.rs.channel[p.Channel].uuids[p.Role] != "" {
err = errors.Errorf("channel '%s' already occupied by role %d", p.Channel, p.Role)
return
}
}
r.Channel = p.Channel
if _, ok := c.rs.channel[r.Channel]; !ok {
c.rs.channel[r.Channel] = newChannelData(r.Channel)
}
// assign UUID for the role in the channel
c.rs.channel[r.Channel].uuids[p.Role] = uuid4.New().String()
r.UUID = c.rs.channel[r.Channel].uuids[p.Role]
log.Debugf("(%s) %s has joined as role %d", r.Channel, r.UUID, p.Role)
// if channel is not open, set initial parameters
if !c.rs.channel[r.Channel].isopen {
c.rs.channel[r.Channel].isopen = true
c.rs.channel[r.Channel].Ports = tcpPorts
c.rs.channel[r.Channel].startTime = time.Now()
switch curve := p.Curve; curve {
case "p224":
c.rs.channel[r.Channel].curve = elliptic.P224()
case "p256":
c.rs.channel[r.Channel].curve = elliptic.P256()
case "p384":
c.rs.channel[r.Channel].curve = elliptic.P384()
case "p521":
c.rs.channel[r.Channel].curve = elliptic.P521()
default:
// TODO:
// add SIEC
p.Curve = "p256"
c.rs.channel[r.Channel].curve = elliptic.P256()
}
log.Debugf("(%s) using curve '%s'", r.Channel, p.Curve)
c.rs.channel[r.Channel].State["curve"] = []byte(p.Curve)
}
r.Message = fmt.Sprintf("assigned role %d in channel '%s'", p.Role, r.Channel)
return
}(cg)
if err != nil {
log.Debugf("bad /join: %s", err.Error())
r.Message = err.Error()
r.Success = false
}
bR, _ := json.Marshal(r)
cg.Data(200, "application/json", bR)
})
log.Infof("Running at http://0.0.0.0:" + port)
err = r.Run(":" + port)
return
}
func middleWareHandler() gin.HandlerFunc {
return func(cg *gin.Context) {
t := time.Now()
// Run next function
cg.Next()
// Log request
log.Infof("%v %v %v %s", cg.Request.RemoteAddr, cg.Request.Method, cg.Request.URL, time.Since(t))
}
} }
func (c *Croc) channelCleanup() { func (c *Croc) channelCleanup() {