mirror of
https://github.com/schollz/croc.git
synced 2025-10-10 21:01:02 +02:00
feat: added TCP healthcheck with nc, better clipboard support, fixed docker deployments and minor changes
This commit is contained in:
parent
990696e419
commit
7992dd607a
10 changed files with 70 additions and 37 deletions
4
.github/workflows/deploy.yml
vendored
4
.github/workflows/deploy.yml
vendored
|
@ -45,5 +45,5 @@ jobs:
|
||||||
file: ./Dockerfile
|
file: ./Dockerfile
|
||||||
platforms: linux/amd64,linux/arm,linux/arm64,linux/386
|
platforms: linux/amd64,linux/arm,linux/arm64,linux/386
|
||||||
push: ${{ github.event_name != 'pull_request' }}
|
push: ${{ github.event_name != 'pull_request' }}
|
||||||
tags: ${{ steps.docker_meta.outputs.tags }}
|
tags: ${{ steps.meta.outputs.tags }}
|
||||||
labels: ${{ steps.docker_meta.outputs.labels }}
|
labels: ${{ steps.meta.outputs.labels }}
|
||||||
|
|
6
.gitignore
vendored
6
.gitignore
vendored
|
@ -21,5 +21,9 @@
|
||||||
go.work
|
go.work
|
||||||
go.work.sum
|
go.work.sum
|
||||||
|
|
||||||
# env file
|
# Environment variables file
|
||||||
.env
|
.env
|
||||||
|
|
||||||
|
# Croc builds
|
||||||
|
/croc
|
||||||
|
croc_v*
|
||||||
|
|
|
@ -20,5 +20,9 @@ COPY --from=builder /go/croc/croc /go/croc/croc-entrypoint.sh /
|
||||||
|
|
||||||
USER nobody
|
USER nobody
|
||||||
|
|
||||||
|
# Simple TCP health check with nc!
|
||||||
|
HEALTHCHECK --interval=30s --timeout=10s --start-period=5s --retries=3 \
|
||||||
|
CMD nc -z localhost 9009 || exit 1
|
||||||
|
|
||||||
ENTRYPOINT ["/croc-entrypoint.sh"]
|
ENTRYPOINT ["/croc-entrypoint.sh"]
|
||||||
CMD ["relay"]
|
CMD ["relay"]
|
||||||
|
|
2
main.go
2
main.go
|
@ -47,7 +47,7 @@ func main() {
|
||||||
}()
|
}()
|
||||||
|
|
||||||
// Wait for a termination signal
|
// Wait for a termination signal
|
||||||
_ = <-sigs
|
<-sigs
|
||||||
utils.RemoveMarkedFiles()
|
utils.RemoveMarkedFiles()
|
||||||
|
|
||||||
// Exit the program gracefully
|
// Exit the program gracefully
|
||||||
|
|
|
@ -119,7 +119,7 @@ func Run() (err error) {
|
||||||
&cli.StringFlag{Name: "pass", Value: models.DEFAULT_PASSPHRASE, Usage: "password for the relay", EnvVars: []string{"CROC_PASS"}},
|
&cli.StringFlag{Name: "pass", Value: models.DEFAULT_PASSPHRASE, Usage: "password for the relay", EnvVars: []string{"CROC_PASS"}},
|
||||||
&cli.StringFlag{Name: "socks5", Value: "", Usage: "add a socks5 proxy", EnvVars: []string{"SOCKS5_PROXY"}},
|
&cli.StringFlag{Name: "socks5", Value: "", Usage: "add a socks5 proxy", EnvVars: []string{"SOCKS5_PROXY"}},
|
||||||
&cli.StringFlag{Name: "connect", Value: "", Usage: "add a http proxy", EnvVars: []string{"HTTP_PROXY"}},
|
&cli.StringFlag{Name: "connect", Value: "", Usage: "add a http proxy", EnvVars: []string{"HTTP_PROXY"}},
|
||||||
&cli.StringFlag{Name: "throttleUpload", Value: "", Usage: "Throttle the upload speed e.g. 500k"},
|
&cli.StringFlag{Name: "throttleUpload", Value: "", Usage: "throttle the upload speed e.g. 500k"},
|
||||||
}
|
}
|
||||||
app.EnableBashCompletion = true
|
app.EnableBashCompletion = true
|
||||||
app.HideHelp = false
|
app.HideHelp = false
|
||||||
|
@ -478,9 +478,7 @@ Or you can go back to the classic croc behavior by enabling classic mode:
|
||||||
|
|
||||||
// save the config
|
// save the config
|
||||||
saveConfig(c, crocOptions)
|
saveConfig(c, crocOptions)
|
||||||
|
|
||||||
err = cr.Send(minimalFileInfos, emptyFoldersToTransfer, totalNumberFolders)
|
err = cr.Send(minimalFileInfos, emptyFoldersToTransfer, totalNumberFolders)
|
||||||
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -142,7 +142,9 @@ func (c *Comm) Read() (buf []byte, numBytes int, bs []byte, err error) {
|
||||||
log.Warnf("error setting read deadline: %v", err)
|
log.Warnf("error setting read deadline: %v", err)
|
||||||
}
|
}
|
||||||
// must clear the timeout setting
|
// must clear the timeout setting
|
||||||
defer c.connection.SetDeadline(time.Time{})
|
if err := c.connection.SetDeadline(time.Time{}); err != nil {
|
||||||
|
log.Warnf("failed to clear deadline: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
// read until we get 4 bytes for the magic
|
// read until we get 4 bytes for the magic
|
||||||
header := make([]byte, 4)
|
header := make([]byte, 4)
|
||||||
|
|
|
@ -16,14 +16,27 @@ func TestComm(t *testing.T) {
|
||||||
t.Error(err)
|
t.Error(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
port := "8001"
|
// Use dynamic port allocation to avoid conflicts
|
||||||
|
listener, err := net.Listen("tcp", "127.0.0.1:0")
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
port := listener.Addr().(*net.TCPAddr).Port
|
||||||
|
portStr := listener.Addr().String()
|
||||||
|
listener.Close() // Close the listener so we can reopen it in the goroutine
|
||||||
|
|
||||||
go func() {
|
go func() {
|
||||||
log.Debug("starting TCP server on " + port)
|
log.Debug("starting TCP server on " + portStr)
|
||||||
server, err := net.Listen("tcp", "0.0.0.0:"+port)
|
server, err := net.Listen("tcp", portStr)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Error(err)
|
log.Error(err)
|
||||||
|
return
|
||||||
}
|
}
|
||||||
defer server.Close()
|
defer func() {
|
||||||
|
if err := server.Close(); err != nil {
|
||||||
|
log.Error(err)
|
||||||
|
}
|
||||||
|
}()
|
||||||
// spawn a new goroutine whenever a client connects
|
// spawn a new goroutine whenever a client connects
|
||||||
for {
|
for {
|
||||||
connection, err := server.Accept()
|
connection, err := server.Accept()
|
||||||
|
@ -31,7 +44,7 @@ func TestComm(t *testing.T) {
|
||||||
log.Error(err)
|
log.Error(err)
|
||||||
}
|
}
|
||||||
log.Debugf("client %s connected", connection.RemoteAddr().String())
|
log.Debugf("client %s connected", connection.RemoteAddr().String())
|
||||||
go func(_ string, connection net.Conn) {
|
go func(_ int, connection net.Conn) {
|
||||||
c := New(connection)
|
c := New(connection)
|
||||||
err = c.Send([]byte("hello, world"))
|
err = c.Send([]byte("hello, world"))
|
||||||
assert.Nil(t, err)
|
assert.Nil(t, err)
|
||||||
|
@ -49,7 +62,7 @@ func TestComm(t *testing.T) {
|
||||||
}()
|
}()
|
||||||
|
|
||||||
time.Sleep(300 * time.Millisecond)
|
time.Sleep(300 * time.Millisecond)
|
||||||
a, err := NewConnection("127.0.0.1:"+port, 10*time.Minute)
|
a, err := NewConnection(portStr, 10*time.Minute)
|
||||||
assert.Nil(t, err)
|
assert.Nil(t, err)
|
||||||
data, err := a.Receive()
|
data, err := a.Receive()
|
||||||
assert.Equal(t, []byte("hello, world"), data)
|
assert.Equal(t, []byte("hello, world"), data)
|
||||||
|
|
|
@ -258,6 +258,7 @@ type TransferOptions struct {
|
||||||
KeepPathInRemote bool
|
KeepPathInRemote bool
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// helper function checking for an empty folder
|
||||||
func isEmptyFolder(folderPath string) (bool, error) {
|
func isEmptyFolder(folderPath string) (bool, error) {
|
||||||
f, err := os.Open(folderPath)
|
f, err := os.Open(folderPath)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -313,15 +314,6 @@ func isChild(parentPath, childPath string) bool {
|
||||||
return !strings.HasPrefix(relPath, "..")
|
return !strings.HasPrefix(relPath, "..")
|
||||||
}
|
}
|
||||||
|
|
||||||
func recursiveFiles(path string) (paths []string, err error) {
|
|
||||||
paths = []string{strings.ToLower(path)}
|
|
||||||
err = filepath.Walk(path, func(path string, info os.FileInfo, err error) error {
|
|
||||||
paths = append(paths, strings.ToLower(path))
|
|
||||||
return nil
|
|
||||||
})
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
// This function retrieves the important file information
|
// This function retrieves the important file information
|
||||||
// for every file that will be transferred
|
// for every file that will be transferred
|
||||||
func GetFilesInfo(fnames []string, zipfolder bool, ignoreGit bool, exclusions []string) (filesInfo []FileInfo, emptyFolders []FileInfo, totalNumberFolders int, err error) {
|
func GetFilesInfo(fnames []string, zipfolder bool, ignoreGit bool, exclusions []string) (filesInfo []FileInfo, emptyFolders []FileInfo, totalNumberFolders int, err error) {
|
||||||
|
@ -679,7 +671,7 @@ On the other computer run:
|
||||||
machid, _ := machineid.ID()
|
machid, _ := machineid.ID()
|
||||||
fmt.Fprintf(os.Stderr, "\rYour machine ID is '%s'\n", machid)
|
fmt.Fprintf(os.Stderr, "\rYour machine ID is '%s'\n", machid)
|
||||||
}
|
}
|
||||||
// // 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
|
||||||
// connect to the relay for messaging
|
// connect to the relay for messaging
|
||||||
|
@ -830,8 +822,7 @@ On the other computer run:
|
||||||
|
|
||||||
err = <-errchan
|
err = <-errchan
|
||||||
if err == nil {
|
if err == nil {
|
||||||
// return if no error
|
return // no error
|
||||||
return
|
|
||||||
} else {
|
} else {
|
||||||
log.Debugf("error from errchan: %v", err)
|
log.Debugf("error from errchan: %v", err)
|
||||||
if strings.Contains(err.Error(), "could not secure channel") {
|
if strings.Contains(err.Error(), "could not secure channel") {
|
||||||
|
@ -988,7 +979,6 @@ func (c *Client) Receive() (err error) {
|
||||||
if c.Options.TestFlag || (!usingLocal && !c.Options.DisableLocal && !isIPset) {
|
if c.Options.TestFlag || (!usingLocal && !c.Options.DisableLocal && !isIPset) {
|
||||||
// ask the sender for their local ips and port
|
// ask the sender for their local ips and port
|
||||||
// and try to connect to them
|
// and try to connect to them
|
||||||
|
|
||||||
var ips []string
|
var ips []string
|
||||||
err = func() (err error) {
|
err = func() (err error) {
|
||||||
var A *pake.Pake
|
var A *pake.Pake
|
||||||
|
@ -1291,7 +1281,7 @@ func (c *Client) processMessageFileInfo(m message.Message) (done bool, err error
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// // check the totalSize does not exceed disk space
|
// check the totalSize does not exceed disk space
|
||||||
// usage := diskusage.NewDiskUsage(".")
|
// usage := diskusage.NewDiskUsage(".")
|
||||||
// if usage.Available() < uint64(totalSize) {
|
// if usage.Available() < uint64(totalSize) {
|
||||||
// return true, fmt.Errorf("not enough disk space")
|
// return true, fmt.Errorf("not enough disk space")
|
||||||
|
@ -1455,7 +1445,6 @@ func (c *Client) processMessagePake(m message.Message) (err error) {
|
||||||
}(i)
|
}(i)
|
||||||
}
|
}
|
||||||
wg.Wait()
|
wg.Wait()
|
||||||
|
|
||||||
if !c.Options.IsSender {
|
if !c.Options.IsSender {
|
||||||
log.Debug("sending external IP")
|
log.Debug("sending external IP")
|
||||||
err = message.Send(c.conn[0], c.Key, message.Message{
|
err = message.Send(c.conn[0], c.Key, message.Message{
|
||||||
|
@ -2135,26 +2124,48 @@ func (c *Client) sendData(i int) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// isExecutableInPath checks for the availability of an executable
|
||||||
|
func isExecutableInPath(executableName string) bool {
|
||||||
|
_, err := exec.LookPath(executableName)
|
||||||
|
return err == nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// copyToClipboard tries to send the code to the operating system clipboard
|
||||||
func copyToClipboard(str string) {
|
func copyToClipboard(str string) {
|
||||||
var cmd *exec.Cmd
|
var cmd *exec.Cmd
|
||||||
switch runtime.GOOS {
|
switch runtime.GOOS {
|
||||||
|
// Windows should always have clip.exe in PATH by default
|
||||||
case "windows":
|
case "windows":
|
||||||
cmd = exec.Command("clip")
|
cmd = exec.Command("clip")
|
||||||
|
// MacOS uses pbcopy
|
||||||
case "darwin":
|
case "darwin":
|
||||||
cmd = exec.Command("pbcopy")
|
cmd = exec.Command("pbcopy")
|
||||||
case "linux":
|
// These Unix-like systems are likely using Xorg(with xclip or xsel) or Wayland(with wl-copy)
|
||||||
if os.Getenv("XDG_SESSION_TYPE") == "wayland" {
|
case "linux", "hurd", "freebsd", "openbsd", "netbsd", "dragonfly", "solaris", "illumos", "plan9":
|
||||||
|
if os.Getenv("XDG_SESSION_TYPE") == "wayland" { // Wayland running
|
||||||
cmd = exec.Command("wl-copy")
|
cmd = exec.Command("wl-copy")
|
||||||
|
} else if os.Getenv("XDG_SESSION_TYPE") == "x11" || os.Getenv("XDG_SESSION_TYPE") == "xorg" { // Xorg running
|
||||||
|
if isExecutableInPath("xclip") {
|
||||||
|
cmd = exec.Command("xclip", "-selection", "clipboard")
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
cmd = exec.Command("xclip", "-selection", "clipboard")
|
if isExecutableInPath("xsel") {
|
||||||
|
cmd = exec.Command("xsel", "-b")
|
||||||
|
}
|
||||||
}
|
}
|
||||||
default:
|
default:
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
// Nothing has been found
|
||||||
|
if cmd == nil {
|
||||||
|
log.Warn("system not supported, display server not supported or supported clipboard tool missing!")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
// Sending stdin into the available clipboard program
|
||||||
cmd.Stdin = bytes.NewReader([]byte(str))
|
cmd.Stdin = bytes.NewReader([]byte(str))
|
||||||
if err := cmd.Run(); err != nil {
|
if err := cmd.Run(); err != nil {
|
||||||
log.Debugf("error copying to clipboard: %v", err)
|
log.Debugf("error copying to clipboard: %v", err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
fmt.Fprintf(os.Stderr, "Code copied to clipboard\n")
|
fmt.Fprintf(os.Stderr, "Code copied to clipboard!\n")
|
||||||
}
|
}
|
||||||
|
|
|
@ -46,7 +46,7 @@ func replaceInFile(fname, start, end, replacement string) (err error) {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
oldVersion := GetStringInBetween(string(b), start, end)
|
oldVersion := getStringInBetween(string(b), start, end)
|
||||||
if oldVersion == "" {
|
if oldVersion == "" {
|
||||||
err = fmt.Errorf("nothing")
|
err = fmt.Errorf("nothing")
|
||||||
return
|
return
|
||||||
|
@ -61,8 +61,8 @@ func replaceInFile(fname, start, end, replacement string) (err error) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetStringInBetween Returns empty string if no start string found
|
// getStringInBetween Returns empty string if no start string found
|
||||||
func GetStringInBetween(str string, start string, end string) (result string) {
|
func getStringInBetween(str, start, end string) (result string) {
|
||||||
s := strings.Index(str, start)
|
s := strings.Index(str, start)
|
||||||
if s == -1 {
|
if s == -1 {
|
||||||
return
|
return
|
||||||
|
|
|
@ -281,11 +281,12 @@ func LocalIP() string {
|
||||||
return localAddr.IP.String()
|
return localAddr.IP.String()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// GenerateRandomPin returns a randomly generated pin with set lenght
|
||||||
func GenerateRandomPin() string {
|
func GenerateRandomPin() string {
|
||||||
s := ""
|
s := ""
|
||||||
max := new(big.Int)
|
max := new(big.Int)
|
||||||
max.SetInt64(9)
|
max.SetInt64(9)
|
||||||
for i := 0; i < NbPinNumbers; i++ {
|
for range NbPinNumbers {
|
||||||
v, err := rand.Int(rand.Reader, max)
|
v, err := rand.Int(rand.Reader, max)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(err)
|
panic(err)
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue