mirror of https://github.com/schollz/croc.git
initial part works
This commit is contained in:
parent
972dce1ec5
commit
ac113dfe47
|
@ -152,7 +152,7 @@ func send(c *cli.Context) (err error) {
|
||||||
IsSender: true,
|
IsSender: true,
|
||||||
Debug: c.GlobalBool("debug"),
|
Debug: c.GlobalBool("debug"),
|
||||||
NoPrompt: c.GlobalBool("yes"),
|
NoPrompt: c.GlobalBool("yes"),
|
||||||
AddressRelay: c.GlobalString("relay"),
|
RelayAddress: c.GlobalString("relay"),
|
||||||
Stdout: c.GlobalBool("stdout"),
|
Stdout: c.GlobalBool("stdout"),
|
||||||
})
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -187,7 +187,7 @@ func receive(c *cli.Context) (err error) {
|
||||||
IsSender: false,
|
IsSender: false,
|
||||||
Debug: c.GlobalBool("debug"),
|
Debug: c.GlobalBool("debug"),
|
||||||
NoPrompt: c.GlobalBool("yes"),
|
NoPrompt: c.GlobalBool("yes"),
|
||||||
AddressRelay: c.GlobalString("relay"),
|
RelayAddress: c.GlobalString("relay"),
|
||||||
Stdout: c.GlobalBool("stdout"),
|
Stdout: c.GlobalBool("stdout"),
|
||||||
})
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
277
src/croc/croc.go
277
src/croc/croc.go
|
@ -6,7 +6,6 @@ import (
|
||||||
"encoding/base64"
|
"encoding/base64"
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"fmt"
|
"fmt"
|
||||||
"math"
|
|
||||||
"os"
|
"os"
|
||||||
"path"
|
"path"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
|
@ -16,18 +15,18 @@ import (
|
||||||
|
|
||||||
log "github.com/cihub/seelog"
|
log "github.com/cihub/seelog"
|
||||||
"github.com/denisbrodbeck/machineid"
|
"github.com/denisbrodbeck/machineid"
|
||||||
|
"github.com/pkg/errors"
|
||||||
"github.com/schollz/croc/v6/src/comm"
|
"github.com/schollz/croc/v6/src/comm"
|
||||||
"github.com/schollz/croc/v6/src/crypt"
|
"github.com/schollz/croc/v6/src/crypt"
|
||||||
"github.com/schollz/croc/v6/src/logger"
|
"github.com/schollz/croc/v6/src/logger"
|
||||||
|
"github.com/schollz/croc/v6/src/message"
|
||||||
|
"github.com/schollz/croc/v6/src/tcp"
|
||||||
"github.com/schollz/croc/v6/src/utils"
|
"github.com/schollz/croc/v6/src/utils"
|
||||||
"github.com/schollz/pake"
|
"github.com/schollz/pake"
|
||||||
"github.com/schollz/progressbar/v2"
|
"github.com/schollz/progressbar/v2"
|
||||||
"github.com/schollz/spinner"
|
"github.com/schollz/spinner"
|
||||||
)
|
)
|
||||||
|
|
||||||
const BufferSize = 4096 * 10
|
|
||||||
const Channels = 1
|
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
logger.SetLogLevel("debug")
|
logger.SetLogLevel("debug")
|
||||||
}
|
}
|
||||||
|
@ -44,7 +43,8 @@ type Options struct {
|
||||||
IsSender bool
|
IsSender bool
|
||||||
SharedSecret string
|
SharedSecret string
|
||||||
Debug bool
|
Debug bool
|
||||||
AddressRelay string
|
RelayAddress string
|
||||||
|
RelayPorts []string
|
||||||
Stdout bool
|
Stdout bool
|
||||||
NoPrompt bool
|
NoPrompt bool
|
||||||
}
|
}
|
||||||
|
@ -52,6 +52,7 @@ type Options struct {
|
||||||
type Client struct {
|
type Client struct {
|
||||||
Options Options
|
Options Options
|
||||||
Pake *pake.Pake
|
Pake *pake.Pake
|
||||||
|
Key crypt.Encryption
|
||||||
|
|
||||||
// steps involved in forming relationship
|
// steps involved in forming relationship
|
||||||
Step1ChannelSecured bool
|
Step1ChannelSecured bool
|
||||||
|
@ -68,8 +69,8 @@ type Client struct {
|
||||||
CurrentFile *os.File
|
CurrentFile *os.File
|
||||||
CurrentFileChunks []int64
|
CurrentFileChunks []int64
|
||||||
|
|
||||||
// tcp connectios
|
// tcp connections
|
||||||
conn [17]*comm.Comm
|
conn []*comm.Comm
|
||||||
|
|
||||||
bar *progressbar.ProgressBar
|
bar *progressbar.ProgressBar
|
||||||
spinner *spinner.Spinner
|
spinner *spinner.Spinner
|
||||||
|
@ -79,13 +80,6 @@ type Client struct {
|
||||||
quit chan bool
|
quit chan bool
|
||||||
}
|
}
|
||||||
|
|
||||||
type Message struct {
|
|
||||||
Type string `json:"t,omitempty"`
|
|
||||||
Message string `json:"m,omitempty"`
|
|
||||||
Bytes []byte `json:"b,omitempty"`
|
|
||||||
Num int `json:"n,omitempty"`
|
|
||||||
}
|
|
||||||
|
|
||||||
type Chunk struct {
|
type Chunk struct {
|
||||||
Bytes []byte `json:"b,omitempty"`
|
Bytes []byte `json:"b,omitempty"`
|
||||||
Location int64 `json:"l,omitempty"`
|
Location int64 `json:"l,omitempty"`
|
||||||
|
@ -112,11 +106,6 @@ type SenderInfo struct {
|
||||||
FilesToTransfer []FileInfo
|
FilesToTransfer []FileInfo
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m Message) String() string {
|
|
||||||
b, _ := json.Marshal(m)
|
|
||||||
return string(b)
|
|
||||||
}
|
|
||||||
|
|
||||||
// New establishes a new connection for transfering files between two instances.
|
// New establishes a new connection for transfering files between two instances.
|
||||||
func New(ops Options) (c *Client, err error) {
|
func New(ops Options) (c *Client, err error) {
|
||||||
c = new(Client)
|
c = new(Client)
|
||||||
|
@ -126,6 +115,22 @@ func New(ops Options) (c *Client, err error) {
|
||||||
Debug(c.Options.Debug)
|
Debug(c.Options.Debug)
|
||||||
log.Debugf("options: %+v", c.Options)
|
log.Debugf("options: %+v", c.Options)
|
||||||
|
|
||||||
|
log.Debug("establishing connection")
|
||||||
|
c.conn = make([]*comm.Comm, len(c.Options.RelayPorts))
|
||||||
|
// connect to the relay for messaging
|
||||||
|
c.conn[0], err = tcp.ConnectToTCPServer(fmt.Sprintf("%s:%s", c.Options.RelayAddress, c.Options.RelayPorts[0]), c.Options.SharedSecret)
|
||||||
|
if err != nil {
|
||||||
|
err = errors.Wrap(err, fmt.Sprintf("could not connect to %s:%s", c.Options.RelayAddress, c.Options.RelayPorts[0]))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
log.Debugf("connection established: %+v", c.conn[0])
|
||||||
|
|
||||||
|
// use default key (no encryption, until PAKE succeeds)
|
||||||
|
c.Key, err = crypt.New(nil, nil)
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
// initialize pake
|
// initialize pake
|
||||||
if c.Options.IsSender {
|
if c.Options.IsSender {
|
||||||
c.Pake, err = pake.Init([]byte(c.Options.SharedSecret), 1, elliptic.P521(), 1*time.Microsecond)
|
c.Pake, err = pake.Init([]byte(c.Options.SharedSecret), 1, elliptic.P521(), 1*time.Microsecond)
|
||||||
|
@ -140,6 +145,7 @@ func New(ops Options) (c *Client, err error) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TransferOptions for sending
|
||||||
type TransferOptions struct {
|
type TransferOptions struct {
|
||||||
PathToFiles []string
|
PathToFiles []string
|
||||||
KeepPathInRemote bool
|
KeepPathInRemote bool
|
||||||
|
@ -156,6 +162,8 @@ func (c *Client) Receive() (err error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Client) transfer(options TransferOptions) (err error) {
|
func (c *Client) transfer(options TransferOptions) (err error) {
|
||||||
|
// connect to the server
|
||||||
|
|
||||||
if c.Options.IsSender {
|
if c.Options.IsSender {
|
||||||
c.FilesToTransfer = make([]FileInfo, len(options.PathToFiles))
|
c.FilesToTransfer = make([]FileInfo, len(options.PathToFiles))
|
||||||
totalFilesSize := int64(0)
|
totalFilesSize := int64(0)
|
||||||
|
@ -224,9 +232,9 @@ func (c *Client) transfer(options TransferOptions) (err error) {
|
||||||
c.machineID = machID
|
c.machineID = machID
|
||||||
fmt.Fprintf(os.Stderr, "Sending %s (%s) from your machine, '%s'\n", fname, utils.ByteCountDecimal(totalFilesSize), machID)
|
fmt.Fprintf(os.Stderr, "Sending %s (%s) from your machine, '%s'\n", fname, utils.ByteCountDecimal(totalFilesSize), machID)
|
||||||
fmt.Fprintf(os.Stderr, "Code is: %s\nOn the other computer run\n\ncroc %s\n", c.Options.SharedSecret, c.Options.SharedSecret)
|
fmt.Fprintf(os.Stderr, "Code is: %s\nOn the other computer run\n\ncroc %s\n", c.Options.SharedSecret, c.Options.SharedSecret)
|
||||||
c.spinner.Suffix = " waiting for recipient..."
|
// // c.spinner.Suffix = " waiting for recipient..."
|
||||||
}
|
}
|
||||||
c.spinner.Start()
|
// c.spinner.Start()
|
||||||
// create channel for quitting
|
// create channel for quitting
|
||||||
// quit with c.quit <- true
|
// quit with c.quit <- true
|
||||||
c.quit = make(chan bool)
|
c.quit = make(chan bool)
|
||||||
|
@ -234,10 +242,10 @@ func (c *Client) transfer(options TransferOptions) (err error) {
|
||||||
// if recipient, initialize with sending pake information
|
// if recipient, initialize with sending pake information
|
||||||
log.Debug("ready")
|
log.Debug("ready")
|
||||||
if !c.Options.IsSender && !c.Step1ChannelSecured {
|
if !c.Options.IsSender && !c.Step1ChannelSecured {
|
||||||
err = c.redisdb.Publish(c.nameOutChannel, Message{
|
err = message.Send(c.conn[0], c.Key, message.Message{
|
||||||
Type: "pake",
|
Type: "pake",
|
||||||
Bytes: c.Pake.Bytes(),
|
Bytes: c.Pake.Bytes(),
|
||||||
}.String()).Err()
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
@ -245,70 +253,63 @@ func (c *Client) transfer(options TransferOptions) (err error) {
|
||||||
|
|
||||||
// listen for incoming messages and process them
|
// listen for incoming messages and process them
|
||||||
for {
|
for {
|
||||||
select {
|
var data []byte
|
||||||
case <-c.quit:
|
data, err = c.conn[0].Receive()
|
||||||
return
|
|
||||||
case msg := <-c.incomingMessageChannel:
|
|
||||||
var m Message
|
|
||||||
err = json.Unmarshal([]byte(msg.Payload), &m)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if m.Type == "finished" {
|
err = c.processMessage(data)
|
||||||
err = c.redisdb.Publish(c.nameOutChannel, Message{
|
|
||||||
Type: "finished",
|
|
||||||
}.String()).Err()
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
err = c.processMessage(m)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
default:
|
|
||||||
time.Sleep(1 * time.Millisecond)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Client) processMessage(m Message) (err error) {
|
func (c *Client) processMessage(payload []byte) (err error) {
|
||||||
|
m, err := message.Decode(c.Key, payload)
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
switch m.Type {
|
switch m.Type {
|
||||||
case "pake":
|
case "pake":
|
||||||
if c.spinner.Suffix != " performing PAKE..." {
|
// if // c.spinner.Suffix != " performing PAKE..." {
|
||||||
c.spinner.Stop()
|
// // c.spinner.Stop()
|
||||||
c.spinner.Suffix = " performing PAKE..."
|
// // c.spinner.Suffix = " performing PAKE..."
|
||||||
c.spinner.Start()
|
// // c.spinner.Start()
|
||||||
}
|
// }
|
||||||
notVerified := !c.Pake.IsVerified()
|
notVerified := !c.Pake.IsVerified()
|
||||||
err = c.Pake.Update(m.Bytes)
|
err = c.Pake.Update(m.Bytes)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if (notVerified && c.Pake.IsVerified() && !c.Options.IsSender) || !c.Pake.IsVerified() {
|
if (notVerified && c.Pake.IsVerified() && !c.Options.IsSender) || !c.Pake.IsVerified() {
|
||||||
err = c.redisdb.Publish(c.nameOutChannel, Message{
|
err = message.Send(c.conn[0], c.Key, message.Message{
|
||||||
Type: "pake",
|
Type: "pake",
|
||||||
Bytes: c.Pake.Bytes(),
|
Bytes: c.Pake.Bytes(),
|
||||||
}.String()).Err()
|
})
|
||||||
}
|
}
|
||||||
if c.Pake.IsVerified() {
|
if c.Pake.IsVerified() {
|
||||||
log.Debug(c.Pake.SessionKey())
|
log.Debug("session key is verified, generating encryption")
|
||||||
|
key, err := c.Pake.SessionKey()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
c.Key, err = crypt.New(key, []byte(c.Options.SharedSecret))
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
c.Step1ChannelSecured = true
|
c.Step1ChannelSecured = true
|
||||||
}
|
}
|
||||||
case "error":
|
case "error":
|
||||||
c.spinner.Stop()
|
// c.spinner.Stop()
|
||||||
fmt.Print("\r")
|
fmt.Print("\r")
|
||||||
err = fmt.Errorf("peer error: %s", m.Message)
|
err = fmt.Errorf("peer error: %s", m.Message)
|
||||||
return err
|
return err
|
||||||
case "fileinfo":
|
case "fileinfo":
|
||||||
var senderInfo SenderInfo
|
var senderInfo SenderInfo
|
||||||
var decryptedBytes []byte
|
err = json.Unmarshal(m.Bytes, &senderInfo)
|
||||||
key, _ := c.Pake.SessionKey()
|
|
||||||
decryptedBytes, err = crypt.DecryptFromBytes(m.Bytes, key)
|
|
||||||
if err != nil {
|
|
||||||
log.Error(err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
err = json.Unmarshal(decryptedBytes, &senderInfo)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Error(err)
|
log.Error(err)
|
||||||
return
|
return
|
||||||
|
@ -322,14 +323,14 @@ func (c *Client) processMessage(m Message) (err error) {
|
||||||
for _, fi := range c.FilesToTransfer {
|
for _, fi := range c.FilesToTransfer {
|
||||||
totalSize += fi.Size
|
totalSize += fi.Size
|
||||||
}
|
}
|
||||||
c.spinner.Stop()
|
// c.spinner.Stop()
|
||||||
if !c.Options.NoPrompt {
|
if !c.Options.NoPrompt {
|
||||||
fmt.Fprintf(os.Stderr, "\rAccept %s (%s) from machine '%s'? (y/n) ", fname, utils.ByteCountDecimal(totalSize), senderInfo.MachineID)
|
fmt.Fprintf(os.Stderr, "\rAccept %s (%s) from machine '%s'? (y/n) ", fname, utils.ByteCountDecimal(totalSize), senderInfo.MachineID)
|
||||||
if strings.ToLower(strings.TrimSpace(utils.GetInput(""))) != "y" {
|
if strings.ToLower(strings.TrimSpace(utils.GetInput(""))) != "y" {
|
||||||
err = c.redisdb.Publish(c.nameOutChannel, Message{
|
err = message.Send(c.conn[0], c.Key, message.Message{
|
||||||
Type: "error",
|
Type: "error",
|
||||||
Message: "refusing files",
|
Message: "refusing files",
|
||||||
}.String()).Err()
|
})
|
||||||
return fmt.Errorf("refused files")
|
return fmt.Errorf("refused files")
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
@ -339,68 +340,22 @@ func (c *Client) processMessage(m Message) (err error) {
|
||||||
c.Step2FileInfoTransfered = true
|
c.Step2FileInfoTransfered = true
|
||||||
case "recipientready":
|
case "recipientready":
|
||||||
var remoteFile RemoteFileRequest
|
var remoteFile RemoteFileRequest
|
||||||
var decryptedBytes []byte
|
err = json.Unmarshal(m.Bytes, &remoteFile)
|
||||||
key, _ := c.Pake.SessionKey()
|
|
||||||
decryptedBytes, err = crypt.DecryptFromBytes(m.Bytes, key)
|
|
||||||
if err != nil {
|
|
||||||
log.Error(err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
err = json.Unmarshal(decryptedBytes, &remoteFile)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
c.FilesToTransferCurrentNum = remoteFile.FilesToTransferCurrentNum
|
c.FilesToTransferCurrentNum = remoteFile.FilesToTransferCurrentNum
|
||||||
c.CurrentFileChunks = remoteFile.CurrentFileChunks
|
c.CurrentFileChunks = remoteFile.CurrentFileChunks
|
||||||
c.Step3RecipientRequestFile = true
|
c.Step3RecipientRequestFile = true
|
||||||
case "datachannel-offer":
|
|
||||||
err = c.dataChannelReceive()
|
|
||||||
if err != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
err = c.recvSess.SetSDP(m.Message)
|
|
||||||
if err != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
var answer string
|
|
||||||
answer, err = c.recvSess.CreateAnswer()
|
|
||||||
if err != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
// Output the answer in base64 so we can paste it in browser
|
|
||||||
err = c.redisdb.Publish(c.nameOutChannel, Message{
|
|
||||||
Type: "datachannel-answer",
|
|
||||||
Message: answer,
|
|
||||||
Num: m.Num,
|
|
||||||
}.String()).Err()
|
|
||||||
// start receiving data
|
|
||||||
pathToFile := path.Join(c.FilesToTransfer[c.FilesToTransferCurrentNum].FolderRemote, c.FilesToTransfer[c.FilesToTransferCurrentNum].Name)
|
|
||||||
c.spinner.Stop()
|
|
||||||
key, _ := c.Pake.SessionKey()
|
|
||||||
c.recvSess.ReceiveData(pathToFile, c.FilesToTransfer[c.FilesToTransferCurrentNum].Size, key)
|
|
||||||
log.Debug("sending close-sender")
|
|
||||||
err = c.redisdb.Publish(c.nameOutChannel, Message{
|
|
||||||
Type: "close-sender",
|
|
||||||
}.String()).Err()
|
|
||||||
case "datachannel-answer":
|
|
||||||
log.Debug("got answer:", m.Message)
|
|
||||||
// Apply the answer as the remote description
|
|
||||||
err = c.sendSess.SetSDP(m.Message)
|
|
||||||
pathToFile := path.Join(c.FilesToTransfer[c.FilesToTransferCurrentNum].FolderSource, c.FilesToTransfer[c.FilesToTransferCurrentNum].Name)
|
|
||||||
c.spinner.Stop()
|
|
||||||
fmt.Fprintf(os.Stderr, "\r\nTransfering...\n")
|
|
||||||
key, _ := c.Pake.SessionKey()
|
|
||||||
c.sendSess.TransferFile(pathToFile, key)
|
|
||||||
case "close-sender":
|
case "close-sender":
|
||||||
log.Debug("close-sender received...")
|
log.Debug("close-sender received...")
|
||||||
c.Step4FileTransfer = false
|
c.Step4FileTransfer = false
|
||||||
c.Step3RecipientRequestFile = false
|
c.Step3RecipientRequestFile = false
|
||||||
c.sendSess.StopSending()
|
|
||||||
log.Debug("sending close-recipient")
|
log.Debug("sending close-recipient")
|
||||||
err = c.redisdb.Publish(c.nameOutChannel, Message{
|
err = message.Send(c.conn[0], c.Key, message.Message{
|
||||||
Type: "close-recipient",
|
Type: "close-recipient",
|
||||||
Num: m.Num,
|
Num: m.Num,
|
||||||
}.String()).Err()
|
})
|
||||||
case "close-recipient":
|
case "close-recipient":
|
||||||
c.Step4FileTransfer = false
|
c.Step4FileTransfer = false
|
||||||
c.Step3RecipientRequestFile = false
|
c.Step3RecipientRequestFile = false
|
||||||
|
@ -424,11 +379,10 @@ func (c *Client) updateState() (err error) {
|
||||||
log.Error(err)
|
log.Error(err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
key, _ := c.Pake.SessionKey()
|
err = message.Send(c.conn[0], c.Key, message.Message{
|
||||||
err = c.redisdb.Publish(c.nameOutChannel, Message{
|
|
||||||
Type: "fileinfo",
|
Type: "fileinfo",
|
||||||
Bytes: crypt.EncryptToBytes(b, key),
|
Bytes: b,
|
||||||
}.String()).Err()
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
@ -456,9 +410,9 @@ func (c *Client) updateState() (err error) {
|
||||||
if finished {
|
if finished {
|
||||||
// TODO: do the last finishing stuff
|
// TODO: do the last finishing stuff
|
||||||
log.Debug("finished")
|
log.Debug("finished")
|
||||||
err = c.redisdb.Publish(c.nameOutChannel, Message{
|
err = message.Send(c.conn[0], c.Key, message.Message{
|
||||||
Type: "finished",
|
Type: "finished",
|
||||||
}.String()).Err()
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(err)
|
panic(err)
|
||||||
}
|
}
|
||||||
|
@ -472,107 +426,24 @@ func (c *Client) updateState() (err error) {
|
||||||
CurrentFileChunks: c.CurrentFileChunks,
|
CurrentFileChunks: c.CurrentFileChunks,
|
||||||
FilesToTransferCurrentNum: c.FilesToTransferCurrentNum,
|
FilesToTransferCurrentNum: c.FilesToTransferCurrentNum,
|
||||||
})
|
})
|
||||||
key, _ := c.Pake.SessionKey()
|
err = message.Send(c.conn[0], c.Key, message.Message{
|
||||||
err = c.redisdb.Publish(c.nameOutChannel, Message{
|
|
||||||
Type: "recipientready",
|
Type: "recipientready",
|
||||||
Bytes: crypt.EncryptToBytes(bRequest, key),
|
Bytes: bRequest,
|
||||||
}.String()).Err()
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
c.Step3RecipientRequestFile = true
|
c.Step3RecipientRequestFile = true
|
||||||
err = c.dataChannelReceive()
|
// TODO: receive
|
||||||
}
|
}
|
||||||
if c.Options.IsSender && c.Step3RecipientRequestFile && !c.Step4FileTransfer {
|
if c.Options.IsSender && c.Step3RecipientRequestFile && !c.Step4FileTransfer {
|
||||||
log.Debug("start sending data!")
|
log.Debug("start sending data!")
|
||||||
err = c.dataChannelSend()
|
// TODO: send
|
||||||
c.Step4FileTransfer = true
|
c.Step4FileTransfer = true
|
||||||
}
|
}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Client) dataChannelReceive() (err error) {
|
|
||||||
c.recvSess = receiver.NewWith(receiver.Config{})
|
|
||||||
err = c.recvSess.CreateConnection()
|
|
||||||
if err != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
c.recvSess.CreateDataHandler()
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *Client) dataChannelSend() (err error) {
|
|
||||||
c.sendSess = sender.NewWith(sender.Config{
|
|
||||||
Configuration: common.Configuration{
|
|
||||||
OnCompletion: func() {
|
|
||||||
},
|
|
||||||
},
|
|
||||||
})
|
|
||||||
|
|
||||||
if err := c.sendSess.CreateConnection(); err != nil {
|
|
||||||
log.Error(err)
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
if err := c.sendSess.CreateDataChannel(); err != nil {
|
|
||||||
log.Error(err)
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
offer, err := c.sendSess.CreateOffer()
|
|
||||||
if err != nil {
|
|
||||||
log.Error(err)
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
// sending offer
|
|
||||||
err = c.redisdb.Publish(c.nameOutChannel, Message{
|
|
||||||
Type: "datachannel-offer",
|
|
||||||
Message: offer,
|
|
||||||
}.String()).Err()
|
|
||||||
if err != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
// MissingChunks returns the positions of missing chunks.
|
|
||||||
// If file doesn't exist, it returns an empty chunk list (all chunks).
|
|
||||||
// If the file size is not the same as requested, it returns an empty chunk list (all chunks).
|
|
||||||
func MissingChunks(fname string, fsize int64, chunkSize int) (chunks []int64) {
|
|
||||||
fstat, err := os.Stat(fname)
|
|
||||||
if fstat.Size() != fsize {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
f, err := os.Open(fname)
|
|
||||||
if err != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
defer f.Close()
|
|
||||||
|
|
||||||
buffer := make([]byte, chunkSize)
|
|
||||||
emptyBuffer := make([]byte, chunkSize)
|
|
||||||
chunkNum := 0
|
|
||||||
chunks = make([]int64, int64(math.Ceil(float64(fsize)/float64(chunkSize))))
|
|
||||||
var currentLocation int64
|
|
||||||
for {
|
|
||||||
bytesread, err := f.Read(buffer)
|
|
||||||
if err != nil {
|
|
||||||
break
|
|
||||||
}
|
|
||||||
if bytes.Equal(buffer[:bytesread], emptyBuffer[:bytesread]) {
|
|
||||||
chunks[chunkNum] = currentLocation
|
|
||||||
}
|
|
||||||
currentLocation += int64(bytesread)
|
|
||||||
}
|
|
||||||
if chunkNum == 0 {
|
|
||||||
chunks = []int64{}
|
|
||||||
} else {
|
|
||||||
chunks = chunks[:chunkNum]
|
|
||||||
}
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
// Encode encodes the input in base64
|
// Encode encodes the input in base64
|
||||||
// It can optionally zip the input before encoding
|
// It can optionally zip the input before encoding
|
||||||
func Encode(obj interface{}) string {
|
func Encode(obj interface{}) string {
|
||||||
|
|
|
@ -3,9 +3,9 @@ package message
|
||||||
import (
|
import (
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
|
|
||||||
|
"github.com/schollz/croc/v6/src/comm"
|
||||||
"github.com/schollz/croc/v6/src/compress"
|
"github.com/schollz/croc/v6/src/compress"
|
||||||
"github.com/schollz/croc/v6/src/crypt"
|
"github.com/schollz/croc/v6/src/crypt"
|
||||||
"github.com/schollz/croc/v6/src/comm"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// Message is the possible payload for messaging
|
// Message is the possible payload for messaging
|
||||||
|
@ -22,8 +22,8 @@ func (m Message) String() string {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Send will send out
|
// Send will send out
|
||||||
func Send(c *comm.Comm, m Message) (err error) {
|
func Send(c *comm.Comm, key crypt.Encryption, m Message) (err error) {
|
||||||
mSend, err := Encode(m)
|
mSend, err := Encode(key, m)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
@ -32,27 +32,22 @@ return
|
||||||
}
|
}
|
||||||
|
|
||||||
// Encode will convert to bytes
|
// Encode will convert to bytes
|
||||||
func Encode(m Message, e ...crypt.Encryption) (b []byte, err error) {
|
func Encode(key crypt.Encryption, m Message) (b []byte, err error) {
|
||||||
b, err = json.Marshal(m)
|
b, err = json.Marshal(m)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
b = compress.Compress(b)
|
b = compress.Compress(b)
|
||||||
if len(e) > 0 {
|
b, err = key.Encrypt(b)
|
||||||
b, err = e[0].Encrypt(b)
|
|
||||||
}
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// Decode will convert from bytes
|
// Decode will convert from bytes
|
||||||
func Decode(b []byte, e ...crypt.Encryption) (m Message, err error) {
|
func Decode(key crypt.Encryption, b []byte) (m Message, err error) {
|
||||||
if len(e) > 0 {
|
b, err = key.Decrypt(b)
|
||||||
b, err = e[0].Decrypt(b)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
}
|
|
||||||
b = compress.Decompress(b)
|
b = compress.Decompress(b)
|
||||||
err = json.Unmarshal(b, &m)
|
err = json.Unmarshal(b, &m)
|
||||||
return
|
return
|
||||||
|
|
|
@ -10,14 +10,14 @@ import (
|
||||||
|
|
||||||
func TestMessage(t *testing.T) {
|
func TestMessage(t *testing.T) {
|
||||||
m := Message{Type: "message", Message: "hello, world"}
|
m := Message{Type: "message", Message: "hello, world"}
|
||||||
e, err := crypt.New([]byte("passphrase"), nil)
|
e, err := crypt.New(nil, nil)
|
||||||
assert.Nil(t, err)
|
assert.Nil(t, err)
|
||||||
fmt.Println(e.Salt())
|
fmt.Println(e.Salt())
|
||||||
b, err := Encode(m, e)
|
b, err := Encode(e, m)
|
||||||
assert.Nil(t, err)
|
assert.Nil(t, err)
|
||||||
fmt.Printf("%x\n", b)
|
fmt.Printf("%x\n", b)
|
||||||
|
|
||||||
m2, err := Decode(b, e)
|
m2, err := Decode(e, b)
|
||||||
assert.Nil(t, err)
|
assert.Nil(t, err)
|
||||||
assert.Equal(t, m, m2)
|
assert.Equal(t, m, m2)
|
||||||
}
|
}
|
||||||
|
|
|
@ -9,7 +9,9 @@ import (
|
||||||
"io"
|
"io"
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
"log"
|
"log"
|
||||||
|
"bytes"
|
||||||
"net"
|
"net"
|
||||||
|
"math"
|
||||||
"net/http"
|
"net/http"
|
||||||
"os"
|
"os"
|
||||||
"strings"
|
"strings"
|
||||||
|
@ -109,3 +111,43 @@ func ByteCountDecimal(b int64) string {
|
||||||
}
|
}
|
||||||
return fmt.Sprintf("%.1f %cB", float64(b)/float64(div), "kMGTPE"[exp])
|
return fmt.Sprintf("%.1f %cB", float64(b)/float64(div), "kMGTPE"[exp])
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// MissingChunks returns the positions of missing chunks.
|
||||||
|
// If file doesn't exist, it returns an empty chunk list (all chunks).
|
||||||
|
// If the file size is not the same as requested, it returns an empty chunk list (all chunks).
|
||||||
|
func MissingChunks(fname string, fsize int64, chunkSize int) (chunks []int64) {
|
||||||
|
fstat, err := os.Stat(fname)
|
||||||
|
if fstat.Size() != fsize {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
f, err := os.Open(fname)
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
defer f.Close()
|
||||||
|
|
||||||
|
buffer := make([]byte, chunkSize)
|
||||||
|
emptyBuffer := make([]byte, chunkSize)
|
||||||
|
chunkNum := 0
|
||||||
|
chunks = make([]int64, int64(math.Ceil(float64(fsize)/float64(chunkSize))))
|
||||||
|
var currentLocation int64
|
||||||
|
for {
|
||||||
|
bytesread, err := f.Read(buffer)
|
||||||
|
if err != nil {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
if bytes.Equal(buffer[:bytesread], emptyBuffer[:bytesread]) {
|
||||||
|
chunks[chunkNum] = currentLocation
|
||||||
|
}
|
||||||
|
currentLocation += int64(bytesread)
|
||||||
|
}
|
||||||
|
if chunkNum == 0 {
|
||||||
|
chunks = []int64{}
|
||||||
|
} else {
|
||||||
|
chunks = chunks[:chunkNum]
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in New Issue