works server<->server

This commit is contained in:
Zack Scholl 2019-11-11 22:03:12 -08:00
parent 5b5e97277e
commit 3847e5d1ad
9 changed files with 831 additions and 9 deletions

11
go.mod
View File

@ -3,12 +3,21 @@ module github.com/schollz/croc/v7
go 1.13
require (
github.com/denisbrodbeck/machineid v1.0.1
github.com/gin-contrib/cors v1.3.0
github.com/gin-gonic/gin v1.4.0
github.com/gorilla/mux v1.7.3
github.com/gorilla/websocket v1.4.1
github.com/pion/webrtc/v2 v2.1.12
github.com/pions/webrtc v1.2.0
github.com/pkg/errors v0.8.1
github.com/schollz/croc/v6 v6.2.0
github.com/schollz/logger v1.0.1
github.com/schollz/pake v1.1.1
github.com/schollz/pake/v2 v2.0.1
golang.org/x/crypto v0.0.0-20191001170739-f9e2070545dc
github.com/schollz/peerdiscovery v1.4.1
github.com/schollz/progressbar/v2 v2.14.0
github.com/schollz/spinner v0.0.0-20180925172146-6bbc5f7804f9
github.com/stretchr/testify v1.4.0
golang.org/x/crypto v0.0.0-20191002192127-34f69633bfdc
)

64
go.sum
View File

@ -1,6 +1,18 @@
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU=
github.com/OneOfOne/xxhash v1.2.5/go.mod h1:eZbhyaAYD41SGSSsnmcpxVoRiQ/MPUTjUdIIOT9Um7Q=
github.com/cespare/xxhash v1.1.0 h1:a6HrQnmkObjyL+Gs60czilIUGqrzKutQD6XZog3p+ko=
github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc=
github.com/cheekybits/genny v1.0.0/go.mod h1:+tQajlRqAUrPI7DOSpB0XAqZYtQakVtB7wXkRAgjxjQ=
github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU=
github.com/cpuguy83/go-md2man/v2 v2.0.0/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/denisbrodbeck/machineid v1.0.1 h1:geKr9qtkB876mXguW2X6TU4ZynleN6ezuMSRhl4D7AQ=
github.com/denisbrodbeck/machineid v1.0.1/go.mod h1:dJUwb7PTidGDeYyUBmXZ2GphQBbjJCrnectwCyxcUSI=
github.com/fatih/color v1.7.0 h1:DkWD4oS2D8LGGgTQ6IvwJJXSL5Vp2ffcQg58nFV38Ys=
github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4=
github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
github.com/gin-contrib/cors v1.3.0 h1:PolezCc89peu+NgkIWt9OB01Kbzt6IP0J/JvkG6xxlg=
github.com/gin-contrib/cors v1.3.0/go.mod h1:artPvLlhkF7oG06nK8v3U8TNz6IeX+w1uzCSEId5/Vc=
@ -18,13 +30,22 @@ github.com/gorilla/websocket v1.4.1 h1:q7AeDBpnBk8AogcD4DSag/Ukw/KV+YhzLj2bP5HvK
github.com/gorilla/websocket v1.4.1/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU=
github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU=
github.com/kalafut/imohash v1.0.0 h1:LgCJ+p/BwM2HKpOxFopkeddpzVCfm15EtXMroXD1SYE=
github.com/kalafut/imohash v1.0.0/go.mod h1:c3RHT80ZAp5C/aYgQI92ZlrOymqkZnRDprU87kg75HI=
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
github.com/lucas-clemente/quic-go v0.7.1-0.20190401152353-907071221cf9/go.mod h1:PpMmPfPKO9nKJ/psF49ESTAGQSdfXxlg1otPbEB2nOw=
github.com/marten-seemann/qtls v0.2.3/go.mod h1:xzjG7avBwGGbdZ8dTGxlBnLArsVKLvwmjgmPuiQEcYk=
github.com/mattn/go-colorable v0.1.4 h1:snbPLB8fVfU9iwbbo30TPtbLRzwWu6aJS6Xh4eaaviA=
github.com/mattn/go-colorable v0.1.4/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE=
github.com/mattn/go-isatty v0.0.7 h1:UvyT9uN+3r7yLEYSlJsbQGdsaB/a0DlgWP3pql6iwOc=
github.com/mattn/go-isatty v0.0.7/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s=
github.com/mattn/go-isatty v0.0.8/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s=
github.com/mattn/go-isatty v0.0.9 h1:d5US/mDsogSGW37IV293h//ZFaeajb69h+EHFsv2xGg=
github.com/mattn/go-isatty v0.0.9/go.mod h1:YNRxwqDuOph6SZLI9vUUz6OYw3QyUt7WiY2yME+cCiQ=
github.com/mitchellh/colorstring v0.0.0-20190213212951-d06e56a500db h1:62I3jR2EmQ4l5rM/4FEfDWcRD+abF5XlKShorW5LRoQ=
github.com/mitchellh/colorstring v0.0.0-20190213212951-d06e56a500db/go.mod h1:l0dey0ia/Uv7NcFFVbCLtqEBQbrT4OCwCSKTEv6enCw=
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
@ -64,34 +85,70 @@ github.com/pion/turn v1.4.0/go.mod h1:aDSi6hWX/hd1+gKia9cExZOR0MU95O7zX9p3Gw/P2a
github.com/pion/webrtc v1.2.0 h1:3LGGPQEMacwG2hcDfhdvwQPz315gvjZXOfY4vaF4+I4=
github.com/pion/webrtc/v2 v2.1.12 h1:x/K+Hwj1Iud+62rA3KaCCAugFWIofzxgBvDEyc1KQmM=
github.com/pion/webrtc/v2 v2.1.12/go.mod h1:CYstxYIn64VLKMmqTHgLvJRnYIF9Ofr4APJXsCVpeso=
github.com/pions/dtls v1.0.2 h1:VOIp3whGooFWS4X0RBOXaykNORYr05yjs8mlNYqRc+4=
github.com/pions/dtls v1.0.2/go.mod h1:T22vu8VCOxNmIrbe3nnM1UdIo3m1Bx5CJNkHyehahLg=
github.com/pions/pkg v0.0.0-20181115215726-b60cd756f712 h1:ciXO7F7PusyAzW/EZJt01bETgfTxP/BIGoWQ15pBP54=
github.com/pions/pkg v0.0.0-20181115215726-b60cd756f712/go.mod h1:r9wKZs+Xxv2acLspex4CHQiIhFjGK1zGP+nUm/8klXA=
github.com/pions/webrtc v1.2.0 h1:U/UYMmhlVF9c1S2cfYZhR+frL0daetdP6yQnWOQzhJo=
github.com/pions/webrtc v1.2.0/go.mod h1:bih1dMY7qksVxZTG2XMjIA6J7D5b92+MJzXYe+G2kng=
github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pkg/errors v0.8.1 h1:iURUrRGxPUNPdy5/HRSm+Yj6okJ6UtLINN0Q9M4+h3I=
github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
github.com/schollz/croc v3.0.6+incompatible h1:rCfc8MGgcGjNW2/qSoulPh8CRGH+Ej4i3RWYOwhX9pE=
github.com/schollz/croc/v6 v6.2.0 h1:pNx9Hb8/EPJX6QAJzyueIwo3kOXzQAQfmF+BLe91ykE=
github.com/schollz/croc/v6 v6.2.0/go.mod h1:mKBKbjrHYdJGqx2U38K4UazJ+nkmfHlWI9FrKdVl8mE=
github.com/schollz/logger v1.0.1 h1:BuBAU+euqphM0Ny9qFVScl4RSxatis4nCHIkOxO2cUU=
github.com/schollz/logger v1.0.1/go.mod h1:P6F4/dGMGcx8wh+kG1zrNEd4vnNpEBY/mwEMd/vn6AM=
github.com/schollz/mnemonicode v1.0.1 h1:LiH5hwADZwjwnfXsaD4xgnMyTAtaKHN+e5AyjRU6WSU=
github.com/schollz/mnemonicode v1.0.1/go.mod h1:cl4UAOhUV0mkdjMj/QYaUZbZZdF8BnOqoz8rHMzwboY=
github.com/schollz/pake v1.1.1 h1:QKeojDWzdAdtRC4m89b6HAxw/8gjqrVu7r4SAOxOFg8=
github.com/schollz/pake v1.1.1/go.mod h1:aWMxQ1jwqZRwk3StflHcdyzPR+CyW5W7+WIZD6Y3dEY=
github.com/schollz/pake/v2 v2.0.1 h1:mvDqzFhKdYw2jG7Wk66DD6qtzkKepQ+Q6vd06rURY0E=
github.com/schollz/pake/v2 v2.0.1/go.mod h1:3uXB571UYJ8Eqh2EEohXe/aO32QID+Varb4GeYA//yw=
github.com/schollz/peerdiscovery v1.4.1 h1:xtZ/D8/4eq9O6UEhRupZZiJm4BA8+u1IVUgeHo5VPm4=
github.com/schollz/peerdiscovery v1.4.1/go.mod h1:WDdk0/JVyVHVIA/bmhzTkUg32dhJ20O4tExNqV1u6sk=
github.com/schollz/progressbar v1.0.0 h1:gbyFReLHDkZo8mxy/dLWMr+Mpb1MokGJ1FqCiqacjZM=
github.com/schollz/progressbar/v2 v2.13.2/go.mod h1:6YZjqdthH6SCZKv2rqGryrxPtfmRB/DWZxSMfCXPyD8=
github.com/schollz/progressbar/v2 v2.14.0 h1:vo7bdkI9E4/CIk9DnL5uVIaybLQiVtiCC2vO+u9j5IM=
github.com/schollz/progressbar/v2 v2.14.0/go.mod h1:6YZjqdthH6SCZKv2rqGryrxPtfmRB/DWZxSMfCXPyD8=
github.com/schollz/spinner v0.0.0-20180925172146-6bbc5f7804f9 h1:y08o5oQ/slxXE/F0uh5dd8mdVvb+w4NLcNSDSq4c2F0=
github.com/schollz/spinner v0.0.0-20180925172146-6bbc5f7804f9/go.mod h1:kCMoQsqzx4MzGJWaALr6tKyCnlrY0kILGLkA1FOiLF4=
github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc=
github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA=
github.com/spaolacci/murmur3 v1.1.0 h1:7c1g84S4BPRrfL5Xrdp6fOJ206sU9y293DDHaoy0bLI=
github.com/spaolacci/murmur3 v1.1.0/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
github.com/stretchr/testify v1.4.0 h1:2E4SXV/wtOkTonXsotYi4li6zVWxYlZuYNCXe9XRJyk=
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
github.com/tscholl2/siec v0.0.0-20180721101609-21667da05937 h1:lhssCpSe3TjKcbvUoPzFMuv9oUyZDgI3Cmgolfw2C90=
github.com/tscholl2/siec v0.0.0-20180721101609-21667da05937/go.mod h1:KL9+ubr1JZdaKjgAaHr+tCytEncXBa1pR6FjbTsOJnw=
github.com/ugorji/go v1.1.4 h1:j4s+tAvLfL3bZyefP2SEWmhBzmuIlH/eqNuPdFPgngw=
github.com/ugorji/go v1.1.4/go.mod h1:uQMGLiO92mf5W77hV/PUCpI3pbzQx3CRekS0kk+RGrc=
github.com/urfave/cli v1.22.1/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0=
golang.org/x/crypto v0.0.0-20181203042331-505ab145d0a9/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
golang.org/x/crypto v0.0.0-20190228161510-8dd112bcdc25/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2 h1:VklqNMn3ovrHsnt90PveolxSbWFaJdECFbxSq0Mqo2M=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/crypto v0.0.0-20190701094942-4def268fd1a4/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20190907121410-71b5226ff739 h1:Gc7JIyxvWgD6m+QmVryY0MstDORNYididDGxgZ6Tnpk=
golang.org/x/crypto v0.0.0-20190907121410-71b5226ff739/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20191001170739-f9e2070545dc h1:KyTYo8xkh/2WdbFLUyQwBS0Jfn3qfZ9QmuPbok2oENE=
golang.org/x/crypto v0.0.0-20191001170739-f9e2070545dc/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20191002192127-34f69633bfdc h1:c0o/qxkaO2LF5t6fQrT4b5hzyggAkLLlCUjqfRxd8Q4=
golang.org/x/crypto v0.0.0-20191002192127-34f69633bfdc/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20181220203305-927f97764cc3/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20190503192946-f4e77d36d62c/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20190619014844-b5b0513f8c1b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20190724013045-ca1201d0de80/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20190930134127-c5a3c61f89f3/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20191003171128-d98b1b443823/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20191021144547-ec77196f6094 h1:5O4U9trLjNpuhpynaDsqwCk+Tw6seqJz1EbqbnzHrc8=
golang.org/x/net v0.0.0-20191021144547-ec77196f6094/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
@ -102,10 +159,15 @@ golang.org/x/sys v0.0.0-20190228124157-a34e9553db1e/go.mod h1:STP8DvDyc/dI5b8T5h
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190507160741-ecd444e8653b h1:ag/x1USPSsqHud38I9BAC88qdNLDHHtQ4mlgQIZPPNA=
golang.org/x/sys v0.0.0-20190507160741-ecd444e8653b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190801041406-cbf593c0f2f3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190813064441-fde4db37ae7a/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20191001151750-bb3f8db39f24/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20191023151326-f89234f9a2c2 h1:I7efaDQAsIQmkTF+WSdcydwVWzK07Yuz8IFF8rNkDe0=
golang.org/x/sys v0.0.0-20191023151326-f89234f9a2c2/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.2 h1:tW2bmiBqwgJj/UpqtC8EpXEZVYOwU0yG4iWbprSVAcs=
golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
@ -114,7 +176,9 @@ gopkg.in/go-playground/assert.v1 v1.2.1/go.mod h1:9RXL0bg/zibRAgZUYszZSwO/z8Y/a8
gopkg.in/go-playground/validator.v8 v8.18.2 h1:lFB4DoMU6B626w8ny76MV7VX6W2VHct2GVOI3xgiMrQ=
gopkg.in/go-playground/validator.v8 v8.18.2/go.mod h1:RX2a/7Ha8BgOhfk7j780h4/u/RRjR0eouCJSH80/M2Y=
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw=
gopkg.in/tylerb/is.v1 v1.1.2/go.mod h1:9yQB2tyIhZ5oph6Kk5Sq7cJMd9c5Jpa1p3hr9kxzPqo=
gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.2.2 h1:ZCJp+EgiOT7lHqUV2J862kp8Qj64Jo6az82+3Td9dZw=
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.2.4 h1:/eiJrUcujPVeJ3xlSWaiNi3uSVmDGBK1pDHUHAnao1I=
gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=

33
main.go
View File

@ -3,16 +3,47 @@ package main
import (
"flag"
"github.com/schollz/croc/v7/src/croc"
"github.com/schollz/croc/v7/src/relay"
log "github.com/schollz/logger"
)
func main() {
var startRelay bool
var startRelay, startSend, startReceive bool
flag.BoolVar(&startRelay, "relay", false, "start relay")
flag.BoolVar(&startSend, "send", false, "send")
flag.BoolVar(&startReceive, "receive", false, "receive")
flag.Parse()
log.SetLevel("debug")
if startRelay {
relay.Run()
} else if startSend {
c, err := croc.New(croc.Options{
IsSender: true,
SharedSecret: "pass",
RelayAddress: "ws://localhost:8005/ws",
Debug: true,
})
if err != nil {
panic(err)
}
err = c.Send(croc.TransferOptions{})
if err != nil {
panic(err)
}
} else if startReceive {
c, err := croc.New(croc.Options{
IsSender: false,
SharedSecret: "pass",
RelayAddress: "ws://localhost:8005/ws",
Debug: true,
})
if err != nil {
panic(err)
}
err = c.Receive()
if err != nil {
panic(err)
}
}
}

43
src/compress/compress.go Normal file
View File

@ -0,0 +1,43 @@
package compress
import (
"bytes"
"compress/flate"
"io"
)
// CompressWithOption returns compressed data using the specified level
func CompressWithOption(src []byte, level int) []byte {
compressedData := new(bytes.Buffer)
compress(src, compressedData, level)
return compressedData.Bytes()
}
// Compress returns a compressed byte slice.
func Compress(src []byte) []byte {
compressedData := new(bytes.Buffer)
compress(src, compressedData, -2)
return compressedData.Bytes()
}
// Decompress returns a decompressed byte slice.
func Decompress(src []byte) []byte {
compressedData := bytes.NewBuffer(src)
deCompressedData := new(bytes.Buffer)
decompress(compressedData, deCompressedData)
return deCompressedData.Bytes()
}
// compress uses flate to compress a byte slice to a corresponding level
func compress(src []byte, dest io.Writer, level int) {
compressor, _ := flate.NewWriter(dest, level)
compressor.Write(src)
compressor.Close()
}
// compress uses flate to decompress an io.Reader
func decompress(src io.Reader, dest io.Writer) {
decompressor := flate.NewReader(src)
io.Copy(dest, decompressor)
decompressor.Close()
}

View File

@ -0,0 +1,97 @@
package compress
import (
"crypto/rand"
"fmt"
"testing"
"github.com/stretchr/testify/assert"
)
var fable = []byte(`The Frog and the Crocodile
Once, there was a frog who lived in the middle of a swamp. His entire family had lived in that swamp for generations, but this particular frog decided that he had had quite enough wetness to last him a lifetime. He decided that he was going to find a dry place to live instead.
The only thing that separated him from dry land was a swampy, muddy, swiftly flowing river. But the river was home to all sorts of slippery, slittering snakes that loved nothing better than a good, plump frog for dinner, so Frog didn't dare try to swim across.
So for many days, the frog stayed put, hopping along the bank, trying to think of a way to get across.
The snakes hissed and jeered at him, daring him to come closer, but he refused. Occasionally they would slither closer, jaws open to attack, but the frog always leaped out of the way. But no matter how far upstream he searched or how far downstream, the frog wasn't able to find a way across the water.
He had felt certain that there would be a bridge, or a place where the banks came together, yet all he found was more reeds and water. After a while, even the snakes stopped teasing him and went off in search of easier prey.
The frog sighed in frustration and sat to sulk in the rushes. Suddenly, he spotted two big eyes staring at him from the water. The giant log-shaped animal opened its mouth and asked him, "What are you doing, Frog? Surely there are enough flies right there for a meal."
The frog croaked in surprise and leaped away from the crocodile. That creature could swallow him whole in a moment without thinking about it! Once he was a satisfied that he was a safe distance away, he answered. "I'm tired of living in swampy waters, and I want to travel to the other side of the river. But if I swim across, the snakes will eat me."
The crocodile harrumphed in agreement and sat, thinking, for a while. "Well, if you're afraid of the snakes, I could give you a ride across," he suggested.
"Oh no, I don't think so," Frog answered quickly. "You'd eat me on the way over, or go underwater so the snakes could get me!"
"Now why would I let the snakes get you? I think they're a terrible nuisance with all their hissing and slithering! The river would be much better off without them altogether! Anyway, if you're so worried that I might eat you, you can ride on my tail."
The frog considered his offer. He did want to get to dry ground very badly, and there didn't seem to be any other way across the river. He looked at the crocodile from his short, squat buggy eyes and wondered about the crocodile's motives. But if he rode on the tail, the croc couldn't eat him anyway. And he was right about the snakes--no self-respecting crocodile would give a meal to the snakes.
"Okay, it sounds like a good plan to me. Turn around so I can hop on your tail."
The crocodile flopped his tail into the marshy mud and let the frog climb on, then he waddled out to the river. But he couldn't stick his tail into the water as a rudder because the frog was on it -- and if he put his tail in the water, the snakes would eat the frog. They clumsily floated downstream for a ways, until the crocodile said, "Hop onto my back so I can steer straight with my tail." The frog moved, and the journey smoothed out.
From where he was sitting, the frog couldn't see much except the back of Crocodile's head. "Why don't you hop up on my head so you can see everything around us?" Crocodile invited. `)
func BenchmarkCompressLevelMinusTwo(b *testing.B) {
for i := 0; i < b.N; i++ {
CompressWithOption(fable, -2)
}
}
func BenchmarkCompressLevelNine(b *testing.B) {
for i := 0; i < b.N; i++ {
CompressWithOption(fable, 9)
}
}
func BenchmarkCompressLevelMinusTwoBinary(b *testing.B) {
data := make([]byte, 1000000)
rand.Read(data)
for i := 0; i < b.N; i++ {
CompressWithOption(data, -2)
}
}
func BenchmarkCompressLevelNineBinary(b *testing.B) {
data := make([]byte, 1000000)
rand.Read(data)
for i := 0; i < b.N; i++ {
CompressWithOption(data, 9)
}
}
func TestCompress(t *testing.T) {
compressedB := CompressWithOption(fable, 9)
dataRateSavings := 100 * (1.0 - float64(len(compressedB))/float64(len(fable)))
fmt.Printf("Level 9: %2.0f%% percent space savings\n", dataRateSavings)
assert.True(t, len(compressedB) < len(fable))
assert.Equal(t, fable, Decompress(compressedB))
compressedB = CompressWithOption(fable, -2)
dataRateSavings = 100 * (1.0 - float64(len(compressedB))/float64(len(fable)))
fmt.Printf("Level -2: %2.0f%% percent space savings\n", dataRateSavings)
assert.True(t, len(compressedB) < len(fable))
compressedB = Compress(fable)
dataRateSavings = 100 * (1.0 - float64(len(compressedB))/float64(len(fable)))
fmt.Printf("Level -2: %2.0f%% percent space savings\n", dataRateSavings)
assert.True(t, len(compressedB) < len(fable))
data := make([]byte, 4096)
rand.Read(data)
compressedB = CompressWithOption(data, -2)
dataRateSavings = 100 * (1.0 - float64(len(compressedB))/float64(len(data)))
fmt.Printf("random, Level -2: %2.0f%% percent space savings\n", dataRateSavings)
rand.Read(data)
compressedB = CompressWithOption(data, 9)
dataRateSavings = 100 * (1.0 - float64(len(compressedB))/float64(len(data)))
fmt.Printf("random, Level 9: %2.0f%% percent space savings\n", dataRateSavings)
}

435
src/croc/croc.go Normal file
View File

@ -0,0 +1,435 @@
package croc
import (
"crypto/elliptic"
"crypto/md5"
"encoding/json"
"fmt"
"time"
"github.com/gorilla/websocket"
"github.com/pion/webrtc/v2"
"github.com/schollz/croc/v7/src/compress"
"github.com/schollz/croc/v7/src/crypt"
log "github.com/schollz/logger"
"github.com/schollz/pake/v2"
)
// Debug toggles debug mode
func Debug(debug bool) {
if debug {
log.SetLevel("debug")
} else {
log.SetLevel("warn")
}
}
// Options specifies user specific options
type Options struct {
IsSender bool
SharedSecret string
Debug bool
RelayAddress string
Stdout bool
NoPrompt bool
DisableLocal bool
Ask bool
}
// Client holds the state of the croc transfer
type Client struct {
// connections
ws *websocket.Conn
rtc *webrtc.PeerConnection
// options
Options Options
// security
Pake *pake.Pake
Key crypt.Encryption
// steps involved in forming relationship
Step1ChannelSecured bool
IsOfferer bool
}
// TransferOptions for sending
type TransferOptions struct {
PathToFiles []string
KeepPathInRemote bool
}
type WebsocketMessage struct {
Message string
Payload []byte
}
func (c *Client) Bundle(payload interface{}) (p []byte, err error) {
p, err = json.Marshal(payload)
if err != nil {
return
}
p = compress.Compress(p)
p, err = c.Key.Encrypt(p)
return
}
func (c *Client) Unbundle(msg []byte, payload interface{}) (err error) {
b, err := c.Key.Decrypt(msg)
if err != nil {
return
}
b = compress.Decompress(b)
err = json.Unmarshal(b, &payload)
return
}
// New establishes a new connection for transferring files between two instances.
func New(ops Options) (c *Client, err error) {
c = new(Client)
// setup basic info
c.Options = ops
if c.Options.Debug {
log.SetLevel("debug")
} else {
log.SetLevel("info")
}
// initialize pake
if c.Options.IsSender {
c.Pake, err = pake.Init([]byte(c.Options.SharedSecret), 1, elliptic.P521(), 1*time.Microsecond)
} else {
c.Pake, err = pake.Init([]byte(c.Options.SharedSecret), 0, elliptic.P521(), 1*time.Microsecond)
}
if err != nil {
return
}
err = c.connectToRelay()
if err != nil {
return
}
if c.IsOfferer {
// offerer sends the first pake
c.ws.WriteJSON(WebsocketMessage{
Payload: c.Pake.Bytes(),
})
} else {
// answerer receives the first pake
err = c.getPAKE(true)
if err != nil {
log.Error(err)
return
}
}
// one more exchange to finish (offerer must send)
err = c.getPAKE(c.IsOfferer)
if err != nil {
log.Error(err)
return
}
log.Debug(c.Pake.SessionKey())
// generate the session key for encryption
pakeSessionKey, err := c.Pake.SessionKey()
if err != nil {
log.Error(err)
return
}
c.Key, err = crypt.New(pakeSessionKey, []byte(c.Options.SharedSecret))
if err != nil {
log.Error(err)
return
}
// create webrtc connection
finished := make(chan error, 1)
c.rtc, err = c.CreateOfferer(finished)
if err != nil {
log.Error(err)
}
offer, err := c.rtc.CreateOffer(nil)
if err != nil {
log.Error(err)
return
}
if c.IsOfferer {
// Now, create an offer
err = c.rtc.SetLocalDescription(offer)
if err != nil {
log.Error(err)
return
}
// bundle it and send it over
var offerJSON []byte
offerJSON, err = json.Marshal(offer)
if err != nil {
log.Error(err)
}
var msg []byte
msg, err = c.Bundle(WebsocketMessage{Message: "offer", Payload: offerJSON})
if err != nil {
log.Error(err)
return
}
err = c.ws.WriteMessage(websocket.BinaryMessage, msg)
if err != nil {
log.Error(err)
return
}
// wait for the answer
_, msg, err = c.ws.ReadMessage()
if err != nil {
log.Error(err)
return
}
var wsmsg WebsocketMessage
err = c.Unbundle(msg, &wsmsg)
if err != nil {
log.Error(err)
return
}
err = setRemoteDescription(c.rtc, wsmsg.Payload)
if err != nil {
log.Error(err)
return
}
} else {
// wait for the offer
var msg []byte
_, msg, err = c.ws.ReadMessage()
if err != nil {
log.Error(err)
return
}
var wsmsg WebsocketMessage
err = c.Unbundle(msg, &wsmsg)
if err != nil {
log.Error(err)
return
}
err = setRemoteDescription(c.rtc, wsmsg.Payload)
if err != nil {
log.Error(err)
return
}
var answer webrtc.SessionDescription
answer, err = c.rtc.CreateAnswer(nil)
if err != nil {
log.Error(err)
return
}
err = c.rtc.SetLocalDescription(answer)
if err != nil {
log.Error(err)
return
}
// bundle it and send it over
var answerJSON []byte
answerJSON, err = json.Marshal(answer)
if err != nil {
log.Error(err)
}
msg, err = c.Bundle(WebsocketMessage{Message: "answer", Payload: answerJSON})
if err != nil {
log.Error(err)
return
}
err = c.ws.WriteMessage(websocket.BinaryMessage, msg)
if err != nil {
log.Error(err)
return
}
}
err = <-finished
return
}
func (c *Client) getPAKE(keepSending bool) (err error) {
// answerer receives the first pake
var p WebsocketMessage
err = c.ws.ReadJSON(&p)
if err != nil {
log.Error(err)
return
}
err = c.Pake.Update(p.Payload)
if err != nil {
log.Error(err)
return
}
if keepSending {
// sends back PAKE bytes
err = c.ws.WriteJSON(WebsocketMessage{
Payload: c.Pake.Bytes(),
})
}
return
}
// Send will send the specified file
func (c *Client) Send(options TransferOptions) (err error) {
return
}
// Receiver will receive the file
func (c *Client) Receive() (err error) {
return
}
func (c *Client) connectToRelay() (err error) {
// connect to relay
websocketURL := c.Options.RelayAddress + "/test1"
log.Debugf("dialing %s", websocketURL)
c.ws, _, err = websocket.DefaultDialer.Dial(websocketURL, nil)
if err != nil {
log.Error("dial:", err)
return
}
c.ws.WriteJSON(WebsocketMessage{
Message: "offerer",
})
var wsmsg WebsocketMessage
err = c.ws.ReadJSON(&wsmsg)
if err != nil {
log.Debug("read:", err)
return
}
log.Debugf("recv: %s", wsmsg)
if wsmsg.Message == "offerer" {
c.IsOfferer = true
c.ws.WriteJSON(WebsocketMessage{
Message: "answerer",
})
} else if wsmsg.Message == "answerer" {
c.IsOfferer = false
} else {
err = fmt.Errorf("got bad message: %+v", wsmsg)
log.Error(err)
}
return
}
const (
bufferedAmountLowThreshold uint64 = 512 * 1024 // 512 KB
maxBufferedAmount uint64 = 1024 * 1024 // 1 MB
maxPacketSize uint64 = 65535
)
func setRemoteDescription(pc *webrtc.PeerConnection, sdp []byte) (err error) {
log.Debug("setting remote description")
var desc webrtc.SessionDescription
err = json.Unmarshal(sdp, &desc)
if err != nil {
log.Error(err)
return
}
log.Debug("applying remote description")
// Apply the desc as the remote description
err = pc.SetRemoteDescription(desc)
if err != nil {
log.Error(err)
}
return
}
func (c *Client) CreateOfferer(finished chan<- error) (pc *webrtc.PeerConnection, err error) {
// Prepare the configuration
config := webrtc.Configuration{
ICEServers: []webrtc.ICEServer{{URLs: []string{"stun:stun.l.google.com:19302"}}},
}
// Create a new PeerConnection
pc, err = webrtc.NewPeerConnection(config)
if err != nil {
log.Error(err)
return
}
ordered := false
maxRetransmits := uint16(0)
options := &webrtc.DataChannelInit{
Ordered: &ordered,
MaxRetransmits: &maxRetransmits,
}
sendMoreCh := make(chan struct{})
// Create a datachannel with label 'data'
dc, err := pc.CreateDataChannel("data", options)
if err != nil {
log.Error(err)
return
}
// Register channel opening handling
sendData := func(buf []byte) error {
fmt.Printf("sent message: %x\n", md5.Sum(buf))
err := dc.Send(buf)
if err != nil {
return err
}
if dc.BufferedAmount()+uint64(len(buf)) > maxBufferedAmount {
// wait until the bufferedAmount becomes lower than the threshold
<-sendMoreCh
}
return nil
}
dc.OnOpen(func() {
fmt.Println(time.Now())
log.Debugf("OnOpen: %s-%d. Start sending a series of 1024-byte packets as fast as it can\n", dc.Label(), dc.ID())
its := 0
for {
its++
msg, _ := c.Bundle(WebsocketMessage{
Message: fmt.Sprintf("%d", its),
})
err2 := sendData(msg)
if err2 != nil {
finished <- err2
return
}
time.Sleep(1 * time.Second)
if its == 30000000 {
break
}
}
})
// Set bufferedAmountLowThreshold so that we can get notified when
// we can send more
dc.SetBufferedAmountLowThreshold(bufferedAmountLowThreshold)
// This callback is made when the current bufferedAmount becomes lower than the threadshold
dc.OnBufferedAmountLow(func() {
sendMoreCh <- struct{}{}
})
// Register the OnMessage to handle incoming messages
dc.OnMessage(func(dcMsg webrtc.DataChannelMessage) {
var wsmsg WebsocketMessage
err := c.Unbundle(dcMsg.Data, &wsmsg)
if err == nil {
log.Debugf("wsmsg: %+v", wsmsg)
} else {
log.Error(err)
}
})
return pc, nil
}

86
src/crypt/crypt.go Normal file
View File

@ -0,0 +1,86 @@
package crypt
import (
"crypto/aes"
"crypto/cipher"
"crypto/rand"
"crypto/sha256"
"golang.org/x/crypto/pbkdf2"
)
// Encryption is the basic type for storing
// the key, passphrase and salt
type Encryption struct {
key []byte
passphrase []byte
salt []byte
}
// New generates a new Encryption, using the supplied passphrase and
// an optional supplied salt.
// Passing nil passphrase will not use decryption.
func New(passphrase []byte, salt []byte) (e Encryption, err error) {
if passphrase == nil {
e = Encryption{nil, nil, nil}
return
}
e.passphrase = passphrase
if salt == nil {
e.salt = make([]byte, 8)
// http://www.ietf.org/rfc/rfc2898.txt
// Salt.
rand.Read(e.salt)
} else {
e.salt = salt
}
e.key = pbkdf2.Key([]byte(passphrase), e.salt, 100, 32, sha256.New)
return
}
// Salt returns the salt bytes
func (e Encryption) Salt() []byte {
return e.salt
}
// Encrypt will generate an Encryption, prefixed with the IV
func (e Encryption) Encrypt(plaintext []byte) (encrypted []byte, err error) {
if e.passphrase == nil {
encrypted = plaintext
return
}
// generate a random iv each time
// http://nvlpubs.nist.gov/nistpubs/Legacy/SP/nistspecialpublication800-38d.pdf
// Section 8.2
ivBytes := make([]byte, 12)
rand.Read(ivBytes)
b, err := aes.NewCipher(e.key)
if err != nil {
return
}
aesgcm, err := cipher.NewGCM(b)
if err != nil {
return
}
encrypted = aesgcm.Seal(nil, ivBytes, plaintext, nil)
encrypted = append(ivBytes, encrypted...)
return
}
// Decrypt an Encryption
func (e Encryption) Decrypt(encrypted []byte) (plaintext []byte, err error) {
if e.passphrase == nil {
plaintext = encrypted
return
}
b, err := aes.NewCipher(e.key)
if err != nil {
return
}
aesgcm, err := cipher.NewGCM(b)
if err != nil {
return
}
plaintext, err = aesgcm.Open(nil, encrypted[:12], encrypted[12:], nil)
return
}

60
src/crypt/crypt_test.go Normal file
View File

@ -0,0 +1,60 @@
package crypt
import (
"testing"
"github.com/stretchr/testify/assert"
)
func BenchmarkEncryptionNew(b *testing.B) {
for i := 0; i < b.N; i++ {
bob, _ := New([]byte("password"), nil)
bob.Encrypt([]byte("hello, world"))
}
}
func BenchmarkEncryption(b *testing.B) {
bob, _ := New([]byte("password"), nil)
for i := 0; i < b.N; i++ {
bob.Encrypt([]byte("hello, world"))
}
}
func TestEncryption(t *testing.T) {
bob, err := New([]byte("password"), nil)
assert.Nil(t, err)
jane, err := New([]byte("password"), bob.Salt())
assert.Nil(t, err)
enc, err := bob.Encrypt([]byte("hello, world"))
assert.Nil(t, err)
dec, err := jane.Decrypt(enc)
assert.Nil(t, err)
assert.Equal(t, dec, []byte("hello, world"))
jane2, err := New([]byte("password"), nil)
assert.Nil(t, err)
dec, err = jane2.Decrypt(enc)
assert.NotNil(t, err)
assert.NotEqual(t, dec, []byte("hello, world"))
jane3, err := New([]byte("passwordwrong"), bob.Salt())
assert.Nil(t, err)
dec, err = jane3.Decrypt(enc)
assert.NotNil(t, err)
assert.NotEqual(t, dec, []byte("hello, world"))
}
func TestNoEncryption(t *testing.T) {
bob, err := New(nil, nil)
assert.Nil(t, err)
jane, err := New(nil, nil)
assert.Nil(t, err)
enc, err := bob.Encrypt([]byte("hello, world"))
assert.Nil(t, err)
dec, err := jane.Decrypt(enc)
assert.Nil(t, err)
assert.Equal(t, dec, []byte("hello, world"))
assert.Equal(t, enc, []byte("hello, world"))
}

View File

@ -137,7 +137,6 @@ func main() {
if sender {
os.Remove("answer.json")
os.Remove("offer.json")
offerPC, err := createOfferer(finished)
if err != nil {
log.Error(err)
@ -192,11 +191,6 @@ func main() {
log.Error(err)
}
err = answerPC.SetLocalDescription(answer)
if err != nil {
log.Error(err)
}
err = setRemoteDescription(answerPC, b)
if err != nil {
log.Error(err)
@ -206,7 +200,10 @@ func main() {
if err != nil {
log.Error(err)
}
err = answerPC.SetLocalDescription(answer)
if err != nil {
log.Error(err)
}
desc2, err := json.Marshal(answer)
if err != nil {