mirror of
https://github.com/schollz/croc.git
synced 2025-01-07 14:50:43 +03:00
receiving file works
This commit is contained in:
parent
98374c31cd
commit
6e27bfebdd
2
main.go
2
main.go
@ -16,7 +16,7 @@ func main() {
|
|||||||
if *role == -1 {
|
if *role == -1 {
|
||||||
err = c.Relay()
|
err = c.Relay()
|
||||||
} else if *role == 0 {
|
} else if *role == 0 {
|
||||||
err = c.Send("foo", *passphrase)
|
err = c.Send("croc.exe", *passphrase)
|
||||||
} else {
|
} else {
|
||||||
err = c.Receive(*passphrase)
|
err = c.Receive(*passphrase)
|
||||||
}
|
}
|
||||||
|
@ -11,7 +11,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, codephrase string) (err error) {
|
func (c *Croc) Send(fname string, codephrase string) (err error) {
|
||||||
err = c.client(0, codephrase)
|
err = c.client(0, codephrase, fname)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
391
src/client.go
391
src/client.go
@ -1,10 +1,17 @@
|
|||||||
package croc
|
package croc
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
"io"
|
||||||
|
"io/ioutil"
|
||||||
"net"
|
"net"
|
||||||
"net/url"
|
"net/url"
|
||||||
"os"
|
"os"
|
||||||
"os/signal"
|
"os/signal"
|
||||||
|
"path"
|
||||||
|
"path/filepath"
|
||||||
|
"strconv"
|
||||||
|
"strings"
|
||||||
"sync"
|
"sync"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
@ -12,11 +19,23 @@ import (
|
|||||||
"github.com/gorilla/websocket"
|
"github.com/gorilla/websocket"
|
||||||
"github.com/pkg/errors"
|
"github.com/pkg/errors"
|
||||||
"github.com/schollz/croc/src/pake"
|
"github.com/schollz/croc/src/pake"
|
||||||
|
tarinator "github.com/schollz/tarinator-go"
|
||||||
)
|
)
|
||||||
|
|
||||||
func (c *Croc) client(role int, codePhrase string) (err error) {
|
func (c *Croc) client(role int, codePhrase string, fname ...string) (err error) {
|
||||||
defer log.Flush()
|
defer log.Flush()
|
||||||
|
|
||||||
|
if role == 0 {
|
||||||
|
if len(fname) == 0 {
|
||||||
|
err = errors.New("must include filename")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
err = c.processFile(fname[0])
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// initialize the channel data for this client
|
// initialize the channel data for this client
|
||||||
c.cs.Lock()
|
c.cs.Lock()
|
||||||
|
|
||||||
@ -63,7 +82,7 @@ func (c *Croc) client(role int, codePhrase string) (err error) {
|
|||||||
log.Debugf("sender read error:", err)
|
log.Debugf("sender read error:", err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
log.Debugf("recv: %s", cd)
|
//log.Debugf("recv: %s", cd.String2())
|
||||||
err = c.processState(ws, cd)
|
err = c.processState(ws, cd)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Warn(err)
|
log.Warn(err)
|
||||||
@ -125,7 +144,7 @@ func (c *Croc) client(role int, codePhrase string) (err error) {
|
|||||||
wg.Wait()
|
wg.Wait()
|
||||||
|
|
||||||
c.cs.Lock()
|
c.cs.Lock()
|
||||||
if c.cs.channel.FileReceived {
|
if c.cs.channel.finishedHappy {
|
||||||
log.Info("file recieved!")
|
log.Info("file recieved!")
|
||||||
}
|
}
|
||||||
c.cs.Unlock()
|
c.cs.Unlock()
|
||||||
@ -148,6 +167,7 @@ func (c *Croc) processState(ws *websocket.Conn, cd channelData) (err error) {
|
|||||||
// if file received, then you are all done
|
// if file received, then you are all done
|
||||||
if cd.FileReceived {
|
if cd.FileReceived {
|
||||||
c.cs.channel.FileReceived = true
|
c.cs.channel.FileReceived = true
|
||||||
|
c.cs.channel.finishedHappy = true
|
||||||
log.Debug("file recieved!")
|
log.Debug("file recieved!")
|
||||||
log.Debug("sending close signal")
|
log.Debug("sending close signal")
|
||||||
c.cs.channel.Close = true
|
c.cs.channel.Close = true
|
||||||
@ -155,7 +175,13 @@ func (c *Croc) processState(ws *websocket.Conn, cd channelData) (err error) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// if transfer ready then send file
|
// otherwise, if ready to read, then set and return
|
||||||
|
if cd.ReadyToRead {
|
||||||
|
c.cs.channel.ReadyToRead = true
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// otherwise, if transfer ready then send file
|
||||||
if cd.TransferReady {
|
if cd.TransferReady {
|
||||||
c.cs.channel.TransferReady = true
|
c.cs.channel.TransferReady = true
|
||||||
return
|
return
|
||||||
@ -181,11 +207,12 @@ func (c *Croc) processState(ws *websocket.Conn, cd channelData) (err error) {
|
|||||||
}
|
}
|
||||||
// copy over the rest of the state
|
// copy over the rest of the state
|
||||||
c.cs.channel.Ports = cd.Ports
|
c.cs.channel.Ports = cd.Ports
|
||||||
|
c.cs.channel.EncryptedFileMetaData = cd.EncryptedFileMetaData
|
||||||
|
|
||||||
// update the Pake
|
// update the Pake
|
||||||
if cd.Pake != nil && cd.Pake.Role != c.cs.channel.Role {
|
if cd.Pake != nil && cd.Pake.Role != c.cs.channel.Role {
|
||||||
log.Debugf("updating pake from %d", cd.Pake.Role)
|
|
||||||
if c.cs.channel.Pake.HkA == nil {
|
if c.cs.channel.Pake.HkA == nil {
|
||||||
|
log.Debugf("updating pake from %d", cd.Pake.Role)
|
||||||
err = c.cs.channel.Pake.Update(cd.Pake.Bytes())
|
err = c.cs.channel.Pake.Update(cd.Pake.Bytes())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Error(err)
|
log.Error(err)
|
||||||
@ -204,54 +231,142 @@ func (c *Croc) processState(ws *websocket.Conn, cd channelData) (err error) {
|
|||||||
c.cs.channel.Update = false
|
c.cs.channel.Update = false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if c.cs.channel.Role == 0 && c.cs.channel.Pake.IsVerified() {
|
if c.cs.channel.Role == 0 && c.cs.channel.Pake.IsVerified() && !c.cs.channel.notSentMetaData {
|
||||||
go func() {
|
go c.getFilesReady(ws)
|
||||||
// encrypt the files
|
|
||||||
// TODO
|
|
||||||
c.cs.Lock()
|
|
||||||
c.cs.channel.fileReady = true
|
|
||||||
c.cs.Unlock()
|
|
||||||
}()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO
|
|
||||||
// process the client state
|
// process the client state
|
||||||
if c.cs.channel.Pake.IsVerified() && !c.cs.channel.isReady {
|
if c.cs.channel.Pake.IsVerified() && !c.cs.channel.isReady && c.cs.channel.EncryptedFileMetaData.Encrypted != nil {
|
||||||
|
// TODO:
|
||||||
|
// check if the user still wants to recieve file
|
||||||
|
|
||||||
|
// decrypt the meta data
|
||||||
|
log.Debugf("encrypted meta data: %+v", c.cs.channel.EncryptedFileMetaData)
|
||||||
|
var passphrase, metaDataBytes []byte
|
||||||
|
passphrase, err = c.cs.channel.Pake.SessionKey()
|
||||||
|
if err != nil {
|
||||||
|
log.Error(err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
metaDataBytes, err = c.cs.channel.EncryptedFileMetaData.decrypt(passphrase)
|
||||||
|
if err != nil {
|
||||||
|
log.Error(err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
err = json.Unmarshal(metaDataBytes, &c.cs.channel.fileMetaData)
|
||||||
|
if err != nil {
|
||||||
|
log.Error(err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
log.Debugf("meta data: %+v", c.cs.channel.fileMetaData)
|
||||||
|
|
||||||
// spawn TCP connections
|
// spawn TCP connections
|
||||||
c.cs.channel.isReady = true
|
c.cs.channel.isReady = true
|
||||||
go func(role int) {
|
go c.spawnConnections(ws, c.cs.channel.Role)
|
||||||
err = c.dialUp()
|
|
||||||
if err == nil {
|
|
||||||
if role == 1 {
|
|
||||||
c.cs.Lock()
|
|
||||||
c.cs.channel.Update = true
|
|
||||||
c.cs.channel.FileReceived = true
|
|
||||||
log.Debugf("got file successfully")
|
|
||||||
errWrite := ws.WriteJSON(c.cs.channel)
|
|
||||||
if errWrite != nil {
|
|
||||||
log.Error(errWrite)
|
|
||||||
}
|
|
||||||
c.cs.channel.Update = false
|
|
||||||
c.cs.Unlock()
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
log.Error(err)
|
|
||||||
}
|
|
||||||
}(c.cs.channel.Role)
|
|
||||||
}
|
}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Croc) dialUp() (err error) {
|
func (c *Croc) getFilesReady(ws *websocket.Conn) (err error) {
|
||||||
|
c.cs.Lock()
|
||||||
|
defer c.cs.Unlock()
|
||||||
|
c.cs.channel.notSentMetaData = true
|
||||||
|
// send metadata
|
||||||
|
|
||||||
|
// wait until data is ready
|
||||||
|
for {
|
||||||
|
if c.cs.channel.fileMetaData.Name != "" {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
c.cs.Unlock()
|
||||||
|
time.Sleep(10 * time.Millisecond)
|
||||||
|
c.cs.Lock()
|
||||||
|
}
|
||||||
|
|
||||||
|
// get passphrase
|
||||||
|
var passphrase []byte
|
||||||
|
passphrase, err = c.cs.channel.Pake.SessionKey()
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
// encrypt file data
|
||||||
|
err = encryptFile(path.Join(c.cs.channel.fileMetaData.Path, c.cs.channel.fileMetaData.Name), c.cs.channel.fileMetaData.Name+".enc", passphrase)
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
c.cs.channel.fileMetaData.IsEncrypted = true
|
||||||
|
// split into pieces to send
|
||||||
|
if err = splitFile(c.cs.channel.fileMetaData.Name+".enc", len(c.cs.channel.Ports)); err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
// remove the file now since we still have pieces
|
||||||
|
if err = os.Remove(c.cs.channel.fileMetaData.Name + ".enc"); err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
// remove compressed archive
|
||||||
|
if c.cs.channel.fileMetaData.IsDir {
|
||||||
|
log.Debug("removing archive: " + c.cs.channel.fileMetaData.Name)
|
||||||
|
if err = os.Remove(c.cs.channel.fileMetaData.Name); err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// encrypt meta data
|
||||||
|
var metaDataBytes []byte
|
||||||
|
metaDataBytes, err = json.Marshal(c.cs.channel.fileMetaData)
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
c.cs.channel.EncryptedFileMetaData = encrypt(metaDataBytes, passphrase)
|
||||||
|
|
||||||
|
c.cs.channel.Update = true
|
||||||
|
log.Debugf("updating channel")
|
||||||
|
errWrite := ws.WriteJSON(c.cs.channel)
|
||||||
|
if errWrite != nil {
|
||||||
|
log.Error(errWrite)
|
||||||
|
}
|
||||||
|
c.cs.channel.Update = false
|
||||||
|
go func() {
|
||||||
|
// encrypt the files
|
||||||
|
// TODO
|
||||||
|
c.cs.Lock()
|
||||||
|
c.cs.channel.fileReady = true
|
||||||
|
c.cs.Unlock()
|
||||||
|
}()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Croc) spawnConnections(ws *websocket.Conn, role int) (err error) {
|
||||||
|
err = c.dialUp(ws)
|
||||||
|
if err == nil {
|
||||||
|
if role == 1 {
|
||||||
|
c.cs.Lock()
|
||||||
|
c.cs.channel.Update = true
|
||||||
|
c.cs.channel.finishedHappy = true
|
||||||
|
c.cs.channel.FileReceived = true
|
||||||
|
log.Debugf("got file successfully")
|
||||||
|
errWrite := ws.WriteJSON(c.cs.channel)
|
||||||
|
if errWrite != nil {
|
||||||
|
log.Error(errWrite)
|
||||||
|
}
|
||||||
|
c.cs.channel.Update = false
|
||||||
|
c.cs.Unlock()
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
log.Error(err)
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Croc) dialUp(ws *websocket.Conn) (err error) {
|
||||||
c.cs.Lock()
|
c.cs.Lock()
|
||||||
ports := c.cs.channel.Ports
|
ports := c.cs.channel.Ports
|
||||||
channel := c.cs.channel.Channel
|
channel := c.cs.channel.Channel
|
||||||
uuid := c.cs.channel.UUID
|
uuid := c.cs.channel.UUID
|
||||||
role := c.cs.channel.Role
|
role := c.cs.channel.Role
|
||||||
c.cs.Unlock()
|
c.cs.Unlock()
|
||||||
errorChan := make(chan error)
|
errorChan := make(chan error, len(ports))
|
||||||
for i, port := range ports {
|
for i, port := range ports {
|
||||||
go func(channel, uuid, port string, i int) {
|
go func(channel, uuid, port string, i int, errorChan chan error) {
|
||||||
if i == 0 {
|
if i == 0 {
|
||||||
log.Debug("dialing up")
|
log.Debug("dialing up")
|
||||||
}
|
}
|
||||||
@ -295,14 +410,42 @@ func (c *Croc) dialUp() (err error) {
|
|||||||
}
|
}
|
||||||
time.Sleep(10 * time.Millisecond)
|
time.Sleep(10 * time.Millisecond)
|
||||||
}
|
}
|
||||||
|
c.cs.RLock()
|
||||||
|
filename := c.cs.channel.fileMetaData.Name + ".enc." + strconv.Itoa(i)
|
||||||
|
c.cs.RUnlock()
|
||||||
if role == 0 {
|
if role == 0 {
|
||||||
log.Debug("send file")
|
log.Debug("send file")
|
||||||
|
for {
|
||||||
|
c.cs.RLock()
|
||||||
|
ready := c.cs.channel.ReadyToRead
|
||||||
|
c.cs.RUnlock()
|
||||||
|
if ready {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
time.Sleep(10 * time.Millisecond)
|
||||||
|
}
|
||||||
|
log.Debug("sending file")
|
||||||
|
err = sendFile(filename, i, connection)
|
||||||
} else {
|
} else {
|
||||||
log.Debug("receive file")
|
go func() {
|
||||||
|
time.Sleep(10 * time.Millisecond)
|
||||||
|
c.cs.Lock()
|
||||||
|
log.Debugf("updating channel with ready to read")
|
||||||
|
c.cs.channel.Update = true
|
||||||
|
c.cs.channel.ReadyToRead = true
|
||||||
|
errWrite := ws.WriteJSON(c.cs.channel)
|
||||||
|
if errWrite != nil {
|
||||||
|
log.Error(errWrite)
|
||||||
|
}
|
||||||
|
c.cs.channel.Update = false
|
||||||
|
c.cs.Unlock()
|
||||||
|
log.Debug("receive file")
|
||||||
|
}()
|
||||||
|
|
||||||
|
err = receiveFile(filename, i, connection)
|
||||||
}
|
}
|
||||||
time.Sleep(3 * time.Second)
|
errorChan <- err
|
||||||
errorChan <- nil
|
}(channel, uuid, port, i, errorChan)
|
||||||
}(channel, uuid, port, i)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// collect errors
|
// collect errors
|
||||||
@ -310,7 +453,173 @@ func (c *Croc) dialUp() (err error) {
|
|||||||
errOne := <-errorChan
|
errOne := <-errorChan
|
||||||
if errOne != nil {
|
if errOne != nil {
|
||||||
log.Warn(errOne)
|
log.Warn(errOne)
|
||||||
|
log.Debug("sending close signal")
|
||||||
|
c.cs.channel.Close = true
|
||||||
|
ws.WriteJSON(c.cs.channel)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
log.Debug("leaving dialup")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (c *Croc) processFile(fname string) (err error) {
|
||||||
|
|
||||||
|
fd := FileMetaData{}
|
||||||
|
|
||||||
|
// first check if it is stdin
|
||||||
|
if fname == "stdin" {
|
||||||
|
var f *os.File
|
||||||
|
f, err = ioutil.TempFile(".", "croc-stdin-")
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
_, err = io.Copy(f, os.Stdin)
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
fname = f.Name()
|
||||||
|
err = f.Close()
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
fd.DeleteAfterSending = true
|
||||||
|
}
|
||||||
|
|
||||||
|
fname = filepath.Clean(fname)
|
||||||
|
// check wether the file is a dir
|
||||||
|
info, err := os.Stat(fname)
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
fd.Path, fd.Name = filepath.Split(fname)
|
||||||
|
if info.Mode().IsDir() {
|
||||||
|
// tar folder
|
||||||
|
err = tarinator.Tarinate([]string{fname}, fd.Name+".tar")
|
||||||
|
if err != nil {
|
||||||
|
log.Error(err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
fd.Name = fd.Name + ".tar"
|
||||||
|
fd.Path = "."
|
||||||
|
fd.IsDir = true
|
||||||
|
fname = path.Join(fd.Path, fd.Name)
|
||||||
|
}
|
||||||
|
fd.Hash, err = hashFile(fname)
|
||||||
|
if err != nil {
|
||||||
|
log.Error(err)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
fd.Size, err = fileSize(fname)
|
||||||
|
if err != nil {
|
||||||
|
err = errors.Wrap(err, "could not determine filesize")
|
||||||
|
log.Error(err)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
c.cs.Lock()
|
||||||
|
defer c.cs.Unlock()
|
||||||
|
c.cs.channel.fileMetaData = fd
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func receiveFile(filename string, id int, connection net.Conn) error {
|
||||||
|
log.Debug("waiting for chunk size from sender")
|
||||||
|
fileSizeBuffer := make([]byte, 10)
|
||||||
|
connection.Read(fileSizeBuffer)
|
||||||
|
fileDataString := strings.Trim(string(fileSizeBuffer), ":")
|
||||||
|
fileSizeInt, _ := strconv.Atoi(fileDataString)
|
||||||
|
chunkSize := int64(fileSizeInt)
|
||||||
|
log.Debugf("chunk size: %d", chunkSize)
|
||||||
|
if chunkSize == 0 {
|
||||||
|
log.Debug(fileSizeBuffer)
|
||||||
|
return errors.New("chunk size is empty!")
|
||||||
|
}
|
||||||
|
|
||||||
|
os.Remove(filename)
|
||||||
|
log.Debug("making " + filename)
|
||||||
|
newFile, err := os.Create(filename)
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
defer newFile.Close()
|
||||||
|
|
||||||
|
log.Debug(id, "waiting for file")
|
||||||
|
var receivedBytes int64
|
||||||
|
receivedFirstBytes := false
|
||||||
|
for {
|
||||||
|
if (chunkSize - receivedBytes) < bufferSize {
|
||||||
|
log.Debugf("%d at the end: %d < %d", id, (chunkSize - receivedBytes), bufferSize)
|
||||||
|
io.CopyN(newFile, connection, (chunkSize - receivedBytes))
|
||||||
|
// Empty the remaining bytes that we don't need from the network buffer
|
||||||
|
if (receivedBytes+bufferSize)-chunkSize < bufferSize {
|
||||||
|
log.Debug(id, "empty remaining bytes from network buffer")
|
||||||
|
connection.Read(make([]byte, (receivedBytes+bufferSize)-chunkSize))
|
||||||
|
}
|
||||||
|
break
|
||||||
|
}
|
||||||
|
written, _ := io.CopyN(newFile, connection, bufferSize)
|
||||||
|
receivedBytes += written
|
||||||
|
if !receivedFirstBytes {
|
||||||
|
receivedFirstBytes = true
|
||||||
|
log.Debug(id, "Receieved first bytes!")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
log.Debug(id, "received file")
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func sendFile(filename string, id int, connection net.Conn) error {
|
||||||
|
// open encrypted file chunk, if it exists
|
||||||
|
log.Debug("opening encrypted file chunk: " + filename)
|
||||||
|
file, err := os.Open(filename)
|
||||||
|
if err != nil {
|
||||||
|
log.Error(err)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
defer file.Close()
|
||||||
|
|
||||||
|
// determine and send the file size to client
|
||||||
|
fi, err := file.Stat()
|
||||||
|
if err != nil {
|
||||||
|
log.Error(err)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
log.Debugf("sending chunk size: %d", fi.Size())
|
||||||
|
log.Debug(connection.RemoteAddr())
|
||||||
|
_, err = connection.Write([]byte(fillString(strconv.FormatInt(int64(fi.Size()), 10), 10)))
|
||||||
|
if err != nil {
|
||||||
|
return errors.Wrap(err, "Problem sending chunk data: ")
|
||||||
|
}
|
||||||
|
|
||||||
|
// rate limit the bandwidth
|
||||||
|
log.Debug("determining rate limiting")
|
||||||
|
rate := 10000
|
||||||
|
throttle := time.NewTicker(time.Second / time.Duration(rate))
|
||||||
|
log.Debugf("rate: %+v", rate)
|
||||||
|
defer throttle.Stop()
|
||||||
|
|
||||||
|
// send the file
|
||||||
|
sendBuffer := make([]byte, bufferSize)
|
||||||
|
totalBytesSent := 0
|
||||||
|
for range throttle.C {
|
||||||
|
_, err := file.Read(sendBuffer)
|
||||||
|
written, _ := connection.Write(sendBuffer)
|
||||||
|
totalBytesSent += written
|
||||||
|
// if errWrite != nil {
|
||||||
|
// errWrite = errors.Wrap(errWrite, "problem writing to connection")
|
||||||
|
// return errWrite
|
||||||
|
// }
|
||||||
|
if err == io.EOF {
|
||||||
|
//End of file reached, break out of for loop
|
||||||
|
log.Debug("EOF")
|
||||||
|
err = nil // not really an error
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
log.Debug("file is sent")
|
||||||
|
log.Debug("removing piece")
|
||||||
|
os.Remove(filename)
|
||||||
|
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
@ -6,7 +6,6 @@ import (
|
|||||||
"crypto/rand"
|
"crypto/rand"
|
||||||
"crypto/sha1"
|
"crypto/sha1"
|
||||||
"crypto/sha256"
|
"crypto/sha256"
|
||||||
"encoding/hex"
|
|
||||||
"fmt"
|
"fmt"
|
||||||
mathrand "math/rand"
|
mathrand "math/rand"
|
||||||
"os"
|
"os"
|
||||||
@ -31,9 +30,17 @@ func getRandomName() string {
|
|||||||
return strings.Join(result, "-")
|
return strings.Join(result, "-")
|
||||||
}
|
}
|
||||||
|
|
||||||
func encrypt(plaintext []byte, passphrase string, dontencrypt ...bool) (encrypted []byte, salt string, iv string) {
|
type encryption struct {
|
||||||
|
Encrypted, Salt, IV []byte
|
||||||
|
}
|
||||||
|
|
||||||
|
func encrypt(plaintext []byte, passphrase []byte, dontencrypt ...bool) encryption {
|
||||||
if len(dontencrypt) > 0 && dontencrypt[0] {
|
if len(dontencrypt) > 0 && dontencrypt[0] {
|
||||||
return plaintext, "salt", "iv"
|
return encryption{
|
||||||
|
Encrypted: plaintext,
|
||||||
|
Salt: []byte("salt"),
|
||||||
|
IV: []byte("iv"),
|
||||||
|
}
|
||||||
}
|
}
|
||||||
key, saltBytes := deriveKey(passphrase, nil)
|
key, saltBytes := deriveKey(passphrase, nil)
|
||||||
ivBytes := make([]byte, 12)
|
ivBytes := make([]byte, 12)
|
||||||
@ -42,26 +49,26 @@ func encrypt(plaintext []byte, passphrase string, dontencrypt ...bool) (encrypte
|
|||||||
rand.Read(ivBytes)
|
rand.Read(ivBytes)
|
||||||
b, _ := aes.NewCipher(key)
|
b, _ := aes.NewCipher(key)
|
||||||
aesgcm, _ := cipher.NewGCM(b)
|
aesgcm, _ := cipher.NewGCM(b)
|
||||||
encrypted = aesgcm.Seal(nil, ivBytes, plaintext, nil)
|
encrypted := aesgcm.Seal(nil, ivBytes, plaintext, nil)
|
||||||
salt = hex.EncodeToString(saltBytes)
|
return encryption{
|
||||||
iv = hex.EncodeToString(ivBytes)
|
Encrypted: encrypted,
|
||||||
return
|
Salt: saltBytes,
|
||||||
|
IV: ivBytes,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func decrypt(data []byte, passphrase string, salt string, iv string, dontencrypt ...bool) (plaintext []byte, err error) {
|
func (e encryption) decrypt(passphrase []byte, dontencrypt ...bool) (plaintext []byte, err error) {
|
||||||
if len(dontencrypt) > 0 && dontencrypt[0] {
|
if len(dontencrypt) > 0 && dontencrypt[0] {
|
||||||
return data, nil
|
return e.Encrypted, nil
|
||||||
}
|
}
|
||||||
saltBytes, _ := hex.DecodeString(salt)
|
key, _ := deriveKey(passphrase, e.Salt)
|
||||||
ivBytes, _ := hex.DecodeString(iv)
|
|
||||||
key, _ := deriveKey(passphrase, saltBytes)
|
|
||||||
b, _ := aes.NewCipher(key)
|
b, _ := aes.NewCipher(key)
|
||||||
aesgcm, _ := cipher.NewGCM(b)
|
aesgcm, _ := cipher.NewGCM(b)
|
||||||
plaintext, err = aesgcm.Open(nil, ivBytes, data, nil)
|
plaintext, err = aesgcm.Open(nil, e.IV, e.Encrypted, nil)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
func deriveKey(passphrase string, salt []byte) ([]byte, []byte) {
|
func deriveKey(passphrase []byte, salt []byte) ([]byte, []byte) {
|
||||||
if salt == nil {
|
if salt == nil {
|
||||||
salt = make([]byte, 8)
|
salt = make([]byte, 8)
|
||||||
// http://www.ietf.org/rfc/rfc2898.txt
|
// http://www.ietf.org/rfc/rfc2898.txt
|
||||||
@ -80,15 +87,15 @@ func hashBytes(data []byte) string {
|
|||||||
return fmt.Sprintf("%x", sum)
|
return fmt.Sprintf("%x", sum)
|
||||||
}
|
}
|
||||||
|
|
||||||
func encryptFile(inputFilename string, outputFilename string, password string) error {
|
func encryptFile(inputFilename string, outputFilename string, password []byte) error {
|
||||||
return cryptFile(inputFilename, outputFilename, password, true)
|
return cryptFile(inputFilename, outputFilename, password, true)
|
||||||
}
|
}
|
||||||
|
|
||||||
func decryptFile(inputFilename string, outputFilename string, password string) error {
|
func decryptFile(inputFilename string, outputFilename string, password []byte) error {
|
||||||
return cryptFile(inputFilename, outputFilename, password, false)
|
return cryptFile(inputFilename, outputFilename, password, false)
|
||||||
}
|
}
|
||||||
|
|
||||||
func cryptFile(inputFilename string, outputFilename string, password string, encrypt bool) error {
|
func cryptFile(inputFilename string, outputFilename string, password []byte, encrypt bool) error {
|
||||||
in, err := os.Open(inputFilename)
|
in, err := os.Open(inputFilename)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
@ -109,7 +116,7 @@ func cryptFile(inputFilename string, outputFilename string, password string, enc
|
|||||||
c := &crypt.Crypter{
|
c := &crypt.Crypter{
|
||||||
HashFunc: sha1.New,
|
HashFunc: sha1.New,
|
||||||
HashSize: sha1.Size,
|
HashSize: sha1.Size,
|
||||||
Key: crypt.NewPbkdf2Key([]byte(password), 32),
|
Key: crypt.NewPbkdf2Key(password, 32),
|
||||||
}
|
}
|
||||||
if encrypt {
|
if encrypt {
|
||||||
if err := c.Encrypt(out, in); err != nil {
|
if err := c.Encrypt(out, in); err != nil {
|
||||||
|
@ -59,6 +59,18 @@ type clientState struct {
|
|||||||
sync.RWMutex
|
sync.RWMutex
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type FileMetaData struct {
|
||||||
|
TempName string
|
||||||
|
Name string
|
||||||
|
Size int
|
||||||
|
Hash string
|
||||||
|
Path string
|
||||||
|
IsDir bool
|
||||||
|
IsEncrypted bool
|
||||||
|
IsCompressed bool
|
||||||
|
DeleteAfterSending bool
|
||||||
|
}
|
||||||
|
|
||||||
type channelData struct {
|
type channelData struct {
|
||||||
// Relay actions
|
// Relay actions
|
||||||
// Open set to true when trying to open
|
// Open set to true when trying to open
|
||||||
@ -81,9 +93,12 @@ type channelData struct {
|
|||||||
Ports []string `json:"ports"`
|
Ports []string `json:"ports"`
|
||||||
// Curve is the type of elliptic curve to use
|
// Curve is the type of elliptic curve to use
|
||||||
Curve string `json:"curve"`
|
Curve string `json:"curve"`
|
||||||
|
// FileMetaData is sent after confirmed
|
||||||
|
EncryptedFileMetaData encryption `json:"encrypted_meta_data"`
|
||||||
// FileReceived specifies that everything was done right
|
// FileReceived specifies that everything was done right
|
||||||
FileReceived bool `json:"file_received"`
|
FileReceived bool `json:"file_received"`
|
||||||
|
// ReadyToRead means that the recipient is ready to read
|
||||||
|
ReadyToRead bool `json:"ready_to_read"`
|
||||||
// Error is sent if there is an error
|
// Error is sent if there is an error
|
||||||
Error string `json:"error"`
|
Error string `json:"error"`
|
||||||
|
|
||||||
@ -101,9 +116,12 @@ type channelData struct {
|
|||||||
// passPhrase is used to generate a session key
|
// passPhrase is used to generate a session key
|
||||||
passPhrase string
|
passPhrase string
|
||||||
// sessionKey
|
// sessionKey
|
||||||
sessionKey []byte
|
sessionKey []byte
|
||||||
isReady bool
|
isReady bool
|
||||||
fileReady bool
|
fileReady bool
|
||||||
|
fileMetaData FileMetaData
|
||||||
|
notSentMetaData bool
|
||||||
|
finishedHappy bool
|
||||||
|
|
||||||
// relay parameters
|
// relay parameters
|
||||||
// isopen determine whether or not the channel has been opened
|
// isopen determine whether or not the channel has been opened
|
||||||
@ -111,7 +129,7 @@ type channelData struct {
|
|||||||
// store a UUID of the parties to prevent other parties from joining
|
// store a UUID of the parties to prevent other parties from joining
|
||||||
uuids [2]string // 0 is sender, 1 is recipient
|
uuids [2]string // 0 is sender, 1 is recipient
|
||||||
// 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 map[string][2]net.Conn
|
||||||
// websocket connections
|
// websocket connections
|
||||||
websocketConn [2]*websocket.Conn
|
websocketConn [2]*websocket.Conn
|
||||||
// startTime is the time that the channel was opened
|
// startTime is the time that the channel was opened
|
||||||
|
15
src/relay.go
15
src/relay.go
@ -83,10 +83,19 @@ func (c *Croc) clientCommuncation(port string, connection net.Conn) (err error)
|
|||||||
if uuid == c.rs.channel[channel].uuids[1] {
|
if uuid == c.rs.channel[channel].uuids[1] {
|
||||||
role = 1
|
role = 1
|
||||||
}
|
}
|
||||||
c.rs.channel[channel].connection[role] = connection
|
|
||||||
|
|
||||||
con1 = c.rs.channel[channel].connection[0]
|
if _, ok := c.rs.channel[channel].connection[port]; !ok {
|
||||||
con2 = c.rs.channel[channel].connection[1]
|
c.rs.channel[channel].connection[port] = [2]net.Conn{nil, nil}
|
||||||
|
}
|
||||||
|
con1 = c.rs.channel[channel].connection[port][0]
|
||||||
|
con2 = c.rs.channel[channel].connection[port][1]
|
||||||
|
if role == 0 {
|
||||||
|
con1 = connection
|
||||||
|
} else {
|
||||||
|
con2 = connection
|
||||||
|
}
|
||||||
|
log.Debug(c.rs.channel[channel].connection[port])
|
||||||
|
c.rs.channel[channel].connection[port] = [2]net.Conn{con1, con2}
|
||||||
ports := c.rs.channel[channel].Ports
|
ports := c.rs.channel[channel].Ports
|
||||||
c.rs.Unlock()
|
c.rs.Unlock()
|
||||||
|
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
package croc
|
package croc
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"net"
|
||||||
"net/http"
|
"net/http"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
@ -77,6 +78,8 @@ func (c *Croc) updateChannel(cd channelData) (err error) {
|
|||||||
// update each
|
// update each
|
||||||
c.rs.channel[cd.Channel].Error = cd.Error
|
c.rs.channel[cd.Channel].Error = cd.Error
|
||||||
c.rs.channel[cd.Channel].FileReceived = cd.FileReceived
|
c.rs.channel[cd.Channel].FileReceived = cd.FileReceived
|
||||||
|
c.rs.channel[cd.Channel].EncryptedFileMetaData = cd.EncryptedFileMetaData
|
||||||
|
c.rs.channel[cd.Channel].ReadyToRead = cd.ReadyToRead
|
||||||
if c.rs.channel[cd.Channel].Pake == nil {
|
if c.rs.channel[cd.Channel].Pake == nil {
|
||||||
c.rs.channel[cd.Channel].Pake = new(pake.Pake)
|
c.rs.channel[cd.Channel].Pake = new(pake.Pake)
|
||||||
}
|
}
|
||||||
@ -91,7 +94,6 @@ func (c *Croc) updateChannel(cd channelData) (err error) {
|
|||||||
c.rs.channel[cd.Channel].Pake.Xᵥ = cd.Pake.Xᵥ
|
c.rs.channel[cd.Channel].Pake.Xᵥ = cd.Pake.Xᵥ
|
||||||
c.rs.channel[cd.Channel].Pake.Yᵤ = cd.Pake.Yᵤ
|
c.rs.channel[cd.Channel].Pake.Yᵤ = cd.Pake.Yᵤ
|
||||||
c.rs.channel[cd.Channel].Pake.Yᵥ = cd.Pake.Yᵥ
|
c.rs.channel[cd.Channel].Pake.Yᵥ = cd.Pake.Yᵥ
|
||||||
// TODO
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -122,6 +124,7 @@ func (c *Croc) joinChannel(ws *websocket.Conn, cd channelData) (channel string,
|
|||||||
log.Debug("creating new channel")
|
log.Debug("creating new channel")
|
||||||
if _, ok := c.rs.channel[cd.Channel]; !ok {
|
if _, ok := c.rs.channel[cd.Channel]; !ok {
|
||||||
c.rs.channel[cd.Channel] = new(channelData)
|
c.rs.channel[cd.Channel] = new(channelData)
|
||||||
|
c.rs.channel[cd.Channel].connection = make(map[string][2]net.Conn)
|
||||||
}
|
}
|
||||||
channel = cd.Channel
|
channel = cd.Channel
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user