-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
0 parents
commit eadf1e9
Showing
11 changed files
with
734,675 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
|
||
received/* | ||
test.go |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,17 @@ | ||
{ | ||
// Use IntelliSense to learn about possible attributes. | ||
// Hover to view descriptions of existing attributes. | ||
// For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 | ||
"version": "0.2.0", | ||
"configurations": [ | ||
{ | ||
"name": "Launch", | ||
"type": "go", | ||
"request": "launch", | ||
"mode": "auto", | ||
"program": "${file}", | ||
"env": {}, | ||
"args": ["-v", "4", "ws://localhost:8989/api", "test2.txt"] | ||
} | ||
] | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,48 @@ | ||
# WScp | ||
|
||
|
||
Do you often need to transfer files around but is constantly harassed by annoying restrictive proxies? | ||
|
||
So this project is for you! | ||
|
||
*WScp* is a state-of-the-art file transfer utility, it uses encrypted websocket communication to hide the fact that you are doing something you probably shouldn't. | ||
|
||
Example usage: | ||
``` | ||
$ go run main.go -p http://user:[email protected] -a -v 2 ws://site.web/api test.txt | ||
..:: WScp ::.. | ||
[+] Sending: test.txt | ||
[+] Destination: ws://site.web/api | ||
- Connecting to ws://site.web/api | ||
- Sending handshake message | ||
- Received valid handshake | ||
- Received valid AES key | ||
- Sending init message | ||
- Received valid encrypted response | ||
- Handshake completed | ||
10.50 Mb - 42 pkt |##################################################| 42 pkt - 10.50 Mb | ||
``` | ||
|
||
Yes, it does come with a progress bar, free of charge | ||
|
||
--- | ||
#### To do | ||
##### Project | ||
- [ ] Add build scripts | ||
- [ ] Add install scripts | ||
- [ ] Improve documentation | ||
##### Server | ||
- [ ] Add server config file | ||
- [ ] Add server flags | ||
- [ ] Improve server logging | ||
- [ ] Add endpoint for file retrieval | ||
##### Client | ||
- [ ] Add client config file | ||
- [ ] Add file download option | ||
##### Transfer Package | ||
- [ ] Improve binary marshaling in order to reduce footprint | ||
##### Both | ||
- [ ] Implement sync request for continuing failed transfers | ||
- [ ] Make better comments |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,182 @@ | ||
package main | ||
|
||
import ( | ||
"encoding/base64" | ||
"flag" | ||
"fmt" | ||
"io/ioutil" | ||
"log" | ||
"net/http" | ||
"net/url" | ||
"os" | ||
"path/filepath" | ||
|
||
"./transfer" | ||
"./transfer/packet" | ||
|
||
"github.com/gorilla/websocket" | ||
) | ||
|
||
var verbose int | ||
var proxy string | ||
var stride int | ||
|
||
var ascii bool | ||
|
||
func parseArgs() (string, string) { | ||
flag.StringVar(&proxy, "p", "", "Enable proxy passthrough.\nFormat: {scheme}://[user[:password]@]{address}[:port]") | ||
flag.IntVar(&verbose, "v", 0, "Enables verbose output.") | ||
flag.IntVar(&stride, "s", 256*1024, "Defines the packet size") | ||
flag.BoolVar(&ascii, "a", false, "Makes progress bar output ASCII only") | ||
flag.Parse() | ||
|
||
if flag.NArg() < 2 { | ||
fmt.Println("Missing arguments!") | ||
log.Fatalf("Usage: %s [-h] [-p {scheme}://[user[:password]@]{address}[:port]] [-v {n}] [-s {n}] [-a] {address} {file}\n", filepath.Base(os.Args[0])) | ||
} | ||
|
||
//fmt.Println(flag.Args()) | ||
//fmt.Println(proxy, verbose) | ||
return flag.Arg(0), flag.Arg(1) | ||
} | ||
|
||
func debugln(s string, i int) { | ||
if verbose >= i { | ||
fmt.Println(s) | ||
} | ||
} | ||
|
||
func parseURL(addr string) *url.URL { | ||
u, err := url.Parse(addr) | ||
if err != nil { | ||
debugln(fmt.Sprintf(" - Address: %s", addr), 2) | ||
log.Fatal("URL PARSING ERROR: ", err) | ||
} | ||
//{scheme: "ws", Host: addr, Path: "/"} | ||
if u.Scheme == "" { | ||
u.Scheme = "ws" | ||
} | ||
|
||
return u | ||
} | ||
|
||
func connect(u *url.URL, p *url.URL) *websocket.Conn { | ||
var dialer *websocket.Dialer | ||
var h http.Header | ||
if u.User != nil { | ||
credentials, _ := url.PathUnescape(u.User.String()) | ||
h = http.Header{"Authorization": {"Basic " + base64.StdEncoding.EncodeToString([]byte(credentials))}} | ||
u.User = nil | ||
} else { | ||
h = nil | ||
} | ||
|
||
debugln(fmt.Sprintf(" - Connecting to %s", u.String()), 1) | ||
|
||
if p != nil { | ||
dialer = &websocket.Dialer{ | ||
Proxy: http.ProxyURL(p), | ||
} | ||
} else { | ||
dialer = websocket.DefaultDialer | ||
} | ||
|
||
c, r, err := dialer.Dial(u.String(), h) | ||
if err != nil { | ||
debugln(string(r.StatusCode), 4) | ||
body, _ := ioutil.ReadAll(r.Body) | ||
debugln(string(body), 4) | ||
// TODO: Play dial up sound when connecting | ||
log.Fatal("Failed to dial address!\nError: ", err) | ||
} | ||
return c | ||
} | ||
|
||
func handshakeConnection(c *websocket.Conn, t *transfer.Transfer) { | ||
handshake := packet.HandshakeMessage{PubKey: t.RSA.Bytes()} | ||
|
||
p := packet.Packet{Type: packet.Handshake} | ||
p.AddContent(handshake) | ||
debugln(" - Sending handshake message", 1) | ||
c.WriteMessage(websocket.BinaryMessage, p.Encode()) | ||
|
||
_, msg, _ := c.ReadMessage() | ||
res := packet.New(t.Decrypt(msg)) | ||
b, _ := res.ParseContent() | ||
debugln(" - Received response", 3) | ||
h := b.(packet.HandshakeMessage) | ||
debugln(" - Received valid handshake", 2) | ||
t.RSA.SetSymmetricKey(h.Key) | ||
debugln(" - Received valid AES key", 2) | ||
debugln(" - Initiating packet processing", 3) | ||
t.InitPackets() | ||
|
||
init := packet.InitMessage{Size: t.Size, Filename: t.Filename, Checksum: t.Checksum, PacketCount: t.PacketCount, Index: t.Index} | ||
p.Type = packet.Init | ||
p.AddContent(init) | ||
debugln(" - Sending init message", 2) | ||
c.WriteMessage(websocket.BinaryMessage, t.Encrypt(p.Encode())) | ||
|
||
_, msg, _ = c.ReadMessage() | ||
debugln(" - Received response", 3) | ||
res = packet.New(t.Decrypt(msg)) | ||
debugln(" - Received valid encrypted response", 2) | ||
if res.Type != packet.Ack { | ||
log.Panicln("Handshake failed\nReceived type: ", res.Type) | ||
} | ||
debugln(" - Received ACK", 3) | ||
debugln(" - Handshake completed", 2) | ||
} | ||
|
||
func sendFile(c *websocket.Conn, t *transfer.Transfer) { | ||
fmt.Println("") | ||
for pkt := range t.Packets { | ||
debugln(fmt.Sprintf(" - Sending packet n° %d", t.Index), 3) | ||
t.Replay = pkt | ||
c.WriteMessage(websocket.BinaryMessage, pkt) | ||
t.PrintProgress(50, ascii) | ||
|
||
_, msg, _ := c.ReadMessage() | ||
res := packet.New(t.Decrypt(msg)) | ||
for res.Type == packet.Replay { | ||
debugln(" - Replay request received", 1) | ||
c.WriteMessage(websocket.BinaryMessage, t.Replay) | ||
|
||
_, msg, _ = c.ReadMessage() | ||
res = packet.New(t.Decrypt(msg)) | ||
} | ||
if res.Type != packet.Ack { | ||
log.Fatalln("Invalid message type received\nType: ", res.Type) | ||
} | ||
debugln(" - Received ACK", 4) | ||
} | ||
fmt.Println("") | ||
} | ||
|
||
func removeCreds(u *url.URL) string { | ||
return fmt.Sprintf("%s://%s%s", u.Scheme, u.Host, u.Path) | ||
} | ||
|
||
func main() { | ||
fmt.Println(" ..:: WScp ::.. ") | ||
addr, filename := parseArgs() | ||
u := parseURL(addr) | ||
fmt.Printf("[+] Sending: %s\n", filename) | ||
var p *url.URL | ||
if proxy != "" { | ||
p = parseURL(proxy) | ||
fmt.Printf("[+] Proxy: %s\n", removeCreds(p)) | ||
} else { | ||
p = nil | ||
} | ||
fmt.Printf("[+] Destination: %s\n\n", removeCreds(u)) | ||
c := connect(u, p) | ||
defer c.WriteMessage(websocket.CloseMessage, websocket.FormatCloseMessage(websocket.CloseNormalClosure, "")) | ||
|
||
t := transfer.New(filename, 1024) | ||
t.UpdateStride(stride) | ||
handshakeConnection(c, t) | ||
sendFile(c, t) | ||
|
||
//done := make(chan struct{}) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,129 @@ | ||
// +build ignore | ||
|
||
package main | ||
|
||
import ( | ||
"io" | ||
"log" | ||
"net/http" | ||
"os" | ||
|
||
"./transfer" | ||
"./transfer/packet" | ||
"github.com/gorilla/websocket" | ||
) | ||
|
||
func checkHash(fd *os.File, checksum string) (bool, bool) { | ||
offset, err := fd.Seek(0, io.SeekCurrent) | ||
if err != nil { | ||
log.Fatalln("Failed to get current file offset while calculating file hash\nError: ", err) | ||
} | ||
_, err = fd.Seek(0, io.SeekStart) | ||
if err != nil { | ||
log.Fatalln("Failed to seek file start while calculating file hash\nError: ", err) | ||
} | ||
hash := transfer.HashFile(fd) | ||
_, err = fd.Seek(offset, io.SeekStart) | ||
if err != nil { | ||
log.Println("Failed to seek file offset while calculating file hash\nError: ", err) | ||
} | ||
//debugln(fmt.Sprintf("Calculated file hash: %s", hash), 3) | ||
|
||
return hash == checksum, err != nil | ||
} | ||
|
||
func transferData(h http.ResponseWriter, r *http.Request) { | ||
//log.Println("Connection received from %s", addr) | ||
upgrader := websocket.Upgrader{} | ||
c, err := upgrader.Upgrade(h, r, nil) | ||
if err != nil { | ||
log.Println("Failed to upgrade connection\nError: ", err) | ||
return | ||
} | ||
defer c.Close() | ||
//debugln("Upgraded connection", 2) | ||
|
||
mt, msg, err := c.ReadMessage() | ||
if err != nil { | ||
log.Panicln("Failed to read message\nError: ", err) | ||
return | ||
} | ||
//debugln(fmt.Sprintf("Read message %u", msg), 5) | ||
p := packet.New(msg) | ||
b, _ := p.ParseContent() | ||
hs := b.(packet.HandshakeMessage) | ||
t := transfer.Handshake(&hs) | ||
|
||
p.Type = packet.Handshake | ||
p.AddContent(packet.HandshakeMessage{ | ||
Key: t.RSA.GenerateSymmetricKey(), | ||
}) | ||
c.WriteMessage(mt, t.PubKey.PubEncrypt(p.Encode())) | ||
|
||
mt, msg, err = c.ReadMessage() | ||
p = packet.New(t.Decrypt(msg)) | ||
b, _ = p.ParseContent() | ||
init := b.(packet.InitMessage) | ||
t.Init(&init, "received") | ||
defer t.Fd.Close() | ||
|
||
p.Type = packet.Ack | ||
p.AddContent(packet.AckMessage{}) | ||
c.WriteMessage(mt, t.Encrypt(p.Encode())) | ||
log.Println("Handshake complete") | ||
log.Print(t) | ||
cache := 0 | ||
|
||
for { | ||
mt, msg, err := c.ReadMessage() | ||
if err != nil { | ||
if e, c := err.(*websocket.CloseError); c && e.Code == 1000 { | ||
log.Println("Transfer session complete") | ||
break | ||
} | ||
log.Println("Error: ", err) | ||
break | ||
} | ||
p = packet.New(t.Decrypt(msg)) | ||
b, _ = p.ParseContent() | ||
content := b.(packet.ContentMessage) | ||
/*hash := sha256.New() // Not really necessary, the crypto layer already does integrity checking | ||
if base64.StdEncoding.EncodeToString(hash.Sum(content.Content)) != content.Checksum { | ||
p := packet.Packet{ | ||
Type: packet.Replay, | ||
} | ||
p.AddContent(packet.ReplayMessage{}) | ||
c.WriteMessage(mt, t.Encrypt(p.Encode())) | ||
i-- | ||
continue | ||
}*/ | ||
n, err := t.Fd.Write(content.Content) | ||
if err != nil { | ||
log.Fatalln("Failed to write to file\nError: ", err) | ||
} | ||
// If cache > 75Mb, commit changes to disk | ||
if cache += n; cache > 78643200 { | ||
t.Fd.Sync() | ||
cache = 0 | ||
} | ||
|
||
p := packet.Packet{ | ||
Type: packet.Ack, | ||
} | ||
p.AddContent(packet.AckMessage{}) | ||
c.WriteMessage(mt, t.Encrypt(p.Encode())) | ||
} | ||
log.Println("Finished writing to file") | ||
if matching, _ := checkHash(t.Fd, t.Checksum); matching { | ||
log.Println("Matching file hash found, file integrity confirmed") | ||
} else { | ||
log.Println("Failed to match file hash, new transfer required") | ||
} | ||
} | ||
|
||
func main() { | ||
addr := "127.0.0.1:8989" | ||
//http.HandleFunc("/", serve) | ||
http.HandleFunc("/api", transferData) | ||
http.ListenAndServe(addr, nil) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
Hello, World! |
Oops, something went wrong.