mirror of
https://github.com/schollz/croc.git
synced 2025-10-11 13:21:00 +02:00
websockets working
This commit is contained in:
parent
7a1f0f66cd
commit
22cd0afd11
5 changed files with 187 additions and 45 deletions
16
main.go
16
main.go
|
@ -1,10 +1,22 @@
|
||||||
package main
|
package main
|
||||||
|
|
||||||
import croc "github.com/schollz/croc/src"
|
import (
|
||||||
|
"flag"
|
||||||
|
|
||||||
|
croc "github.com/schollz/croc/src"
|
||||||
|
)
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
|
var err error
|
||||||
|
role := flag.Int("role", 0, "role number")
|
||||||
|
flag.Parse()
|
||||||
|
|
||||||
c := croc.Init()
|
c := croc.Init()
|
||||||
err := c.Relay()
|
if *role == 0 {
|
||||||
|
err = c.Relay()
|
||||||
|
} else if *role == 1 {
|
||||||
|
err = c.Send("foo")
|
||||||
|
}
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(err)
|
panic(err)
|
||||||
}
|
}
|
||||||
|
|
|
@ -44,7 +44,7 @@ func (c *Croc) Relay() error {
|
||||||
|
|
||||||
// Send will take an existing file or folder and send it through the croc relay
|
// Send will take an existing file or folder and send it through the croc relay
|
||||||
func (c *Croc) Send(fname string) (err error) {
|
func (c *Croc) Send(fname string) (err error) {
|
||||||
|
err = c.send(fname)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -36,6 +36,9 @@ type channelData struct {
|
||||||
// Ports returns which TCP ports to connect to
|
// Ports returns which TCP ports to connect to
|
||||||
Ports []string `json:"ports"`
|
Ports []string `json:"ports"`
|
||||||
|
|
||||||
|
// UUID is sent out only to one person at a time
|
||||||
|
UUID string `json:"uuid"`
|
||||||
|
|
||||||
// Private
|
// Private
|
||||||
// isopen determine whether or not the channel has been opened
|
// isopen determine whether or not the channel has been opened
|
||||||
isopen bool
|
isopen bool
|
||||||
|
@ -74,7 +77,8 @@ type payload struct {
|
||||||
Curve string `json:"curve"`
|
Curve string `json:"curve"`
|
||||||
|
|
||||||
// Update set to true when updating
|
// Update set to true when updating
|
||||||
Update bool `json:"update"`
|
Update bool `json:"update"`
|
||||||
|
UUID string `json:"uuid"`
|
||||||
// State is the state information to be updated
|
// State is the state information to be updated
|
||||||
State map[string][]byte `json:"state"`
|
State map[string][]byte `json:"state"`
|
||||||
|
|
||||||
|
@ -84,7 +88,7 @@ type payload struct {
|
||||||
|
|
||||||
func newChannelData(name string) (cd *channelData) {
|
func newChannelData(name string) (cd *channelData) {
|
||||||
cd = new(channelData)
|
cd = new(channelData)
|
||||||
cd.Name = name
|
cd.Channel = name
|
||||||
cd.State = make(map[string][]byte)
|
cd.State = make(map[string][]byte)
|
||||||
for _, state := range availableStates {
|
for _, state := range availableStates {
|
||||||
cd.State[state] = []byte{}
|
cd.State[state] = []byte{}
|
||||||
|
|
73
src/sender.go
Normal file
73
src/sender.go
Normal file
|
@ -0,0 +1,73 @@
|
||||||
|
package croc
|
||||||
|
|
||||||
|
import (
|
||||||
|
"net/url"
|
||||||
|
"os"
|
||||||
|
"os/signal"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
log "github.com/cihub/seelog"
|
||||||
|
"github.com/gorilla/websocket"
|
||||||
|
)
|
||||||
|
|
||||||
|
func (c *Croc) send(fname string) (err error) {
|
||||||
|
interrupt := make(chan os.Signal, 1)
|
||||||
|
signal.Notify(interrupt, os.Interrupt)
|
||||||
|
|
||||||
|
u := url.URL{Scheme: "ws", Host: "localhost:8003", Path: "/"}
|
||||||
|
log.Debugf("connecting to %s", u.String())
|
||||||
|
|
||||||
|
ws, _, err := websocket.DefaultDialer.Dial(u.String(), nil)
|
||||||
|
if err != nil {
|
||||||
|
log.Error("dial:", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
defer ws.Close()
|
||||||
|
|
||||||
|
done := make(chan struct{})
|
||||||
|
|
||||||
|
go func() {
|
||||||
|
defer close(done)
|
||||||
|
for {
|
||||||
|
var cd channelData
|
||||||
|
err := ws.ReadJSON(&cd)
|
||||||
|
if err != nil {
|
||||||
|
log.Debugf("sender read error:", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
log.Debugf("recv: %+v", cd)
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
|
||||||
|
// initialize
|
||||||
|
err = ws.WriteJSON(payload{
|
||||||
|
Open: true,
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
log.Errorf("problem opening: %s", err.Error())
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
for {
|
||||||
|
select {
|
||||||
|
case <-done:
|
||||||
|
return
|
||||||
|
case <-interrupt:
|
||||||
|
log.Debugf("interrupt")
|
||||||
|
|
||||||
|
// Cleanly close the connection by sending a close message and then
|
||||||
|
// waiting (with timeout) for the server to close the connection.
|
||||||
|
errWrite := ws.WriteMessage(websocket.CloseMessage, websocket.FormatCloseMessage(websocket.CloseNormalClosure, ""))
|
||||||
|
if errWrite != nil {
|
||||||
|
log.Debugf("write close:", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
select {
|
||||||
|
case <-done:
|
||||||
|
case <-time.After(time.Second):
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
133
src/server.go
133
src/server.go
|
@ -2,20 +2,48 @@ package croc
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"crypto/elliptic"
|
"crypto/elliptic"
|
||||||
"encoding/json"
|
"net/http"
|
||||||
"fmt"
|
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
log "github.com/cihub/seelog"
|
log "github.com/cihub/seelog"
|
||||||
"github.com/frankenbeanies/uuid4"
|
"github.com/frankenbeanies/uuid4"
|
||||||
"github.com/gin-gonic/gin"
|
"github.com/gorilla/websocket"
|
||||||
"github.com/pkg/errors"
|
"github.com/pkg/errors"
|
||||||
)
|
)
|
||||||
|
|
||||||
func (c *Croc) updateChannel(p payloadChannel) (r response, err error) {
|
func (c *Croc) startServer(tcpPorts []string, port string) (err error) {
|
||||||
|
// start cleanup on dangling channels
|
||||||
|
go c.channelCleanup()
|
||||||
|
|
||||||
|
var upgrader = websocket.Upgrader{} // use default options
|
||||||
|
http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
|
||||||
|
ws, err := upgrader.Upgrade(w, r, nil)
|
||||||
|
if err != nil {
|
||||||
|
log.Error("upgrade:", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
defer ws.Close()
|
||||||
|
for {
|
||||||
|
var p payload
|
||||||
|
err := ws.ReadJSON(&p)
|
||||||
|
if err != nil {
|
||||||
|
log.Debugf("read:", err)
|
||||||
|
break
|
||||||
|
}
|
||||||
|
err = c.processPayload(ws, p)
|
||||||
|
if err != nil {
|
||||||
|
log.Warn("problem processing payload %+v: %s", err.Error())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
log.Debugf("listening on port %s", c.ServerPort)
|
||||||
|
err = http.ListenAndServe(":"+c.ServerPort, nil)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Croc) updateChannel(p payload) (err error) {
|
||||||
c.rs.Lock()
|
c.rs.Lock()
|
||||||
defer c.rs.Unlock()
|
defer c.rs.Unlock()
|
||||||
r.Success = true
|
|
||||||
|
|
||||||
// determine if channel is invalid
|
// determine if channel is invalid
|
||||||
if _, ok := c.rs.channel[p.Channel]; !ok {
|
if _, ok := c.rs.channel[p.Channel]; !ok {
|
||||||
|
@ -30,13 +58,6 @@ func (c *Croc) updateChannel(p payloadChannel) (r response, err error) {
|
||||||
return
|
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
|
// assign each key provided
|
||||||
assignedKeys := []string{}
|
assignedKeys := []string{}
|
||||||
for key := range p.State {
|
for key := range p.State {
|
||||||
|
@ -50,17 +71,13 @@ func (c *Croc) updateChannel(p payloadChannel) (r response, err error) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// return the current state
|
log.Debugf("assigned %d keys: %v", len(assignedKeys), assignedKeys)
|
||||||
r.Data = c.rs.channel[p.Channel]
|
|
||||||
|
|
||||||
r.Message = fmt.Sprintf("assigned %d keys: %v", len(assignedKeys), assignedKeys)
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Croc) joinChannel(p payloadChannel) (r response, err error) {
|
func (c *Croc) joinChannel(ws *websocket.Conn, p payload) (channel string, err error) {
|
||||||
c.rs.Lock()
|
c.rs.Lock()
|
||||||
defer c.rs.Unlock()
|
defer c.rs.Unlock()
|
||||||
r.Success = true
|
|
||||||
|
|
||||||
// determine if sender or recipient
|
// determine if sender or recipient
|
||||||
if p.Role != 0 && p.Role != 1 {
|
if p.Role != 0 && p.Role != 1 {
|
||||||
|
@ -81,50 +98,86 @@ func (c *Croc) joinChannel(p payloadChannel) (r response, err error) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
r.Channel = p.Channel
|
if _, ok := c.rs.channel[p.Channel]; !ok {
|
||||||
if _, ok := c.rs.channel[r.Channel]; !ok {
|
c.rs.channel[p.Channel] = newChannelData(p.Channel)
|
||||||
c.rs.channel[r.Channel] = newChannelData(r.Channel)
|
|
||||||
}
|
}
|
||||||
|
channel = p.Channel
|
||||||
|
|
||||||
// assign UUID for the role in the channel
|
// assign UUID for the role in the channel
|
||||||
c.rs.channel[r.Channel].uuids[p.Role] = uuid4.New().String()
|
c.rs.channel[p.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", p.Channel, c.rs.channel[p.Channel].uuids[p.Role], p.Role)
|
||||||
log.Debugf("(%s) %s has joined as role %d", r.Channel, r.UUID, p.Role)
|
// send Channel+UUID back to the current person
|
||||||
|
err = ws.WriteJSON(channelData{
|
||||||
|
Channel: p.Channel,
|
||||||
|
UUID: c.rs.channel[p.Channel].uuids[p.Role],
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
// if channel is not open, set initial parameters
|
// if channel is not open, set initial parameters
|
||||||
if !c.rs.channel[r.Channel].isopen {
|
if !c.rs.channel[p.Channel].isopen {
|
||||||
c.rs.channel[r.Channel].isopen = true
|
c.rs.channel[p.Channel].isopen = true
|
||||||
c.rs.channel[r.Channel].Ports = tcpPorts
|
c.rs.channel[p.Channel].Ports = c.TcpPorts
|
||||||
c.rs.channel[r.Channel].startTime = time.Now()
|
c.rs.channel[p.Channel].startTime = time.Now()
|
||||||
switch curve := p.Curve; curve {
|
switch curve := p.Curve; curve {
|
||||||
case "p224":
|
case "p224":
|
||||||
c.rs.channel[r.Channel].curve = elliptic.P224()
|
c.rs.channel[p.Channel].curve = elliptic.P224()
|
||||||
case "p256":
|
case "p256":
|
||||||
c.rs.channel[r.Channel].curve = elliptic.P256()
|
c.rs.channel[p.Channel].curve = elliptic.P256()
|
||||||
case "p384":
|
case "p384":
|
||||||
c.rs.channel[r.Channel].curve = elliptic.P384()
|
c.rs.channel[p.Channel].curve = elliptic.P384()
|
||||||
case "p521":
|
case "p521":
|
||||||
c.rs.channel[r.Channel].curve = elliptic.P521()
|
c.rs.channel[p.Channel].curve = elliptic.P521()
|
||||||
default:
|
default:
|
||||||
// TODO:
|
// TODO:
|
||||||
// add SIEC
|
// add SIEC
|
||||||
p.Curve = "p256"
|
p.Curve = "p256"
|
||||||
c.rs.channel[r.Channel].curve = elliptic.P256()
|
c.rs.channel[p.Channel].curve = elliptic.P256()
|
||||||
}
|
}
|
||||||
log.Debugf("(%s) using curve '%s'", r.Channel, p.Curve)
|
log.Debugf("(%s) using curve '%s'", p.Channel, p.Curve)
|
||||||
c.rs.channel[r.Channel].State["curve"] = []byte(p.Curve)
|
c.rs.channel[p.Channel].State["curve"] = []byte(p.Curve)
|
||||||
}
|
}
|
||||||
|
c.rs.channel[p.Channel].websocketConn[p.Role] = ws
|
||||||
|
|
||||||
r.Message = fmt.Sprintf("assigned role %d in channel '%s'", p.Role, r.Channel)
|
log.Debugf("assigned role %d in channel '%s'", p.Role, p.Channel)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Croc) startServer(tcpPorts []string, port string) (err error) {
|
func (c *Croc) processPayload(ws *websocket.Conn, p payload) (err error) {
|
||||||
// start cleanup on dangling channels
|
if p.Close {
|
||||||
go c.channelCleanup()
|
c.rs.Lock()
|
||||||
|
delete(c.rs.channel, p.Channel)
|
||||||
|
c.rs.Unlock()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
channel := p.Channel
|
||||||
|
if p.Open {
|
||||||
|
channel, err = c.joinChannel(ws, p)
|
||||||
|
} else if p.Update {
|
||||||
|
// update
|
||||||
|
}
|
||||||
|
|
||||||
// TODO:
|
// TODO:
|
||||||
// insert websockets here
|
// relay state logic here
|
||||||
|
|
||||||
|
// send out the data to both sender + receiver each time
|
||||||
|
c.rs.Lock()
|
||||||
|
if _, ok := c.rs.channel[channel]; ok {
|
||||||
|
for role, wsConn := range c.rs.channel[channel].websocketConn {
|
||||||
|
if wsConn == nil {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
log.Debugf("writing latest data %+v to %d", c.rs.channel[channel], role)
|
||||||
|
err = wsConn.WriteJSON(c.rs.channel[channel])
|
||||||
|
if err != nil {
|
||||||
|
log.Debugf("problem writing to role %d: %s", role, err.Error())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
c.rs.Lock()
|
||||||
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Croc) channelCleanup() {
|
func (c *Croc) channelCleanup() {
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue