mirror of https://github.com/schollz/croc.git
works server<->server
This commit is contained in:
parent
5b5e97277e
commit
3847e5d1ad
11
go.mod
11
go.mod
|
@ -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
64
go.sum
|
@ -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
33
main.go
|
@ -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)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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()
|
||||
}
|
|
@ -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)
|
||||
|
||||
}
|
|
@ -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
|
||||
}
|
|
@ -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
|
||||
}
|
|
@ -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"))
|
||||
|
||||
}
|
|
@ -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 {
|
||||
|
|
Loading…
Reference in New Issue