use base64

This commit is contained in:
Zack Scholl 2019-11-12 07:50:12 -08:00
parent 3847e5d1ad
commit 4ab7c44c5b
2 changed files with 169 additions and 143 deletions

View File

@ -3,6 +3,7 @@ package croc
import (
"crypto/elliptic"
"crypto/md5"
"encoding/base64"
"encoding/json"
"fmt"
"time"
@ -85,6 +86,43 @@ func (c *Client) Unbundle(msg []byte, payload interface{}) (err error) {
return
}
// SendWebsocketMessage communicates using base64
func (c *Client) SendWebsocketMessage(wsmsg WebsocketMessage, encrypt bool) (err error) {
var b []byte
if encrypt {
b, err = c.Bundle(wsmsg)
} else {
b, err = json.Marshal(wsmsg)
if err != nil {
log.Error(err)
return
}
}
bd := base64.StdEncoding.EncodeToString(b)
err = c.ws.WriteMessage(1, []byte(bd))
return
}
// ReceiveWebsocketMessage communicates using base64
func (c *Client) ReceiveWebsocketMessage(decrypt bool) (wsmsg WebsocketMessage, err error) {
_, msg, err := c.ws.ReadMessage()
if err != nil {
log.Error(err)
return
}
b, err := base64.StdEncoding.DecodeString(string(msg))
if decrypt {
err = c.Unbundle(b, &wsmsg)
if err != nil {
log.Error(err)
return
}
} else {
err = json.Unmarshal(b, &wsmsg)
}
return
}
// New establishes a new connection for transferring files between two instances.
func New(ops Options) (c *Client, err error) {
c = new(Client)
@ -107,6 +145,8 @@ func New(ops Options) (c *Client, err error) {
return
}
// connect to relay and determine
// whether it is receiver or offerer
err = c.connectToRelay()
if err != nil {
return
@ -114,9 +154,10 @@ func New(ops Options) (c *Client, err error) {
if c.IsOfferer {
// offerer sends the first pake
c.ws.WriteJSON(WebsocketMessage{
c.SendWebsocketMessage(WebsocketMessage{
Message: "pake",
Payload: c.Pake.Bytes(),
})
}, false)
} else {
// answerer receives the first pake
err = c.getPAKE(true)
@ -172,30 +213,19 @@ func New(ops Options) (c *Client, err error) {
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)
err = c.SendWebsocketMessage(
WebsocketMessage{Message: "offer", Payload: offerJSON},
true,
)
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
}
wsmsg, err = c.ReceiveWebsocketMessage(true)
err = setRemoteDescription(c.rtc, wsmsg.Payload)
if err != nil {
log.Error(err)
@ -203,18 +233,8 @@ func New(ops Options) (c *Client, err error) {
}
} 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
}
wsmsg, err = c.ReceiveWebsocketMessage(true)
err = setRemoteDescription(c.rtc, wsmsg.Payload)
if err != nil {
@ -240,16 +260,15 @@ func New(ops Options) (c *Client, err error) {
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)
err = c.SendWebsocketMessage(
WebsocketMessage{Message: "answer", Payload: answerJSON},
true,
)
if err != nil {
log.Error(err)
return
}
}
err = <-finished
@ -258,8 +277,7 @@ func New(ops Options) (c *Client, err error) {
func (c *Client) getPAKE(keepSending bool) (err error) {
// answerer receives the first pake
var p WebsocketMessage
err = c.ws.ReadJSON(&p)
p, err := c.ReceiveWebsocketMessage(false)
if err != nil {
log.Error(err)
return
@ -271,9 +289,10 @@ func (c *Client) getPAKE(keepSending bool) (err error) {
}
if keepSending {
// sends back PAKE bytes
err = c.ws.WriteJSON(WebsocketMessage{
err = c.SendWebsocketMessage(WebsocketMessage{
Message: "pake",
Payload: c.Pake.Bytes(),
})
}, false)
}
return
}
@ -298,6 +317,7 @@ func (c *Client) connectToRelay() (err error) {
return
}
log.Debugf("connected and sending first message")
c.ws.WriteJSON(WebsocketMessage{
Message: "offerer",
})

View File

@ -30,119 +30,125 @@
Base64: <textarea id="remoteSessionDescription"></textarea> <br />
<button onclick="startSession()"> Send Message </button> <br />
<script>
function readBlob(opt_startByte, opt_stopByte) {
function readBlob(opt_startByte, opt_stopByte) {
var files = document.getElementById('files').files;
if (!files.length) {
alert('Please select a file!');
return;
var files = document.getElementById('files').files;
if (!files.length) {
alert('Please select a file!');
return;
}
var file = files[0];
var start = parseInt(opt_startByte) || 0;
var stop = parseInt(opt_stopByte) || file.size - 1;
var reader = new FileReader();
// If we use onloadend, we need to check the readyState.
reader.onloadend = function (evt) {
if (evt.target.readyState == FileReader.DONE) { // DONE == 2
document.getElementById('byte_content').textContent = evt.target.result;
document.getElementById('byte_range').textContent = ['Read bytes: ', start + 1, ' - ', stop + 1,
' of ', file.size, ' byte file'
].join('');
sendMessage(evt.target.result);
}
};
var blob = file.slice(start, stop + 1);
reader.readAsBinaryString(blob);
}
var file = files[0];
var start = parseInt(opt_startByte) || 0;
var stop = parseInt(opt_stopByte) || file.size - 1;
var reader = new FileReader();
// If we use onloadend, we need to check the readyState.
reader.onloadend = function(evt) {
if (evt.target.readyState == FileReader.DONE) { // DONE == 2
document.getElementById('byte_content').textContent = evt.target.result;
document.getElementById('byte_range').textContent = ['Read bytes: ', start + 1, ' - ', stop + 1,
' of ', file.size, ' byte file'
].join('');
sendMessage(evt.target.result);
document.querySelector('.readBytesButtons').addEventListener('click', function (evt) {
if (evt.target.tagName.toLowerCase() == 'button') {
var startByte = evt.target.getAttribute('data-startbyte');
var endByte = evt.target.getAttribute('data-endbyte');
readBlob(startByte, endByte);
}
}, false);
let pc = new RTCPeerConnection({
iceServers: [{
urls: 'stun:stun.l.google.com:19302'
}]
})
let log = msg => {
console.log(msg);
}
pc.onsignalingstatechange = e => log(pc.signalingState)
pc.oniceconnectionstatechange = e => log(pc.iceConnectionState)
pc.onicecandidate = event => {
if (event.candidate === null) {
log(JSON.stringify(pc.localDescription))
}
}
pc.ondatachannel = e => {
let dc = e.channel
log('New DataChannel ' + dc.label)
dc.onclose = () => log('dc has closed')
dc.onopen = () => {
log('dc has opened');
}
dc.onmessage = e => {
log(`Message from DataChannel '${dc.label}' payload '${e.data}'`)
}
window.sendMessage = e => {
let message = e;
if (message === '') {
return alert('Message must not be empty')
}
dc.send(message)
}
}
window.startSession = () => {
pc.setRemoteDescription(new RTCSessionDescription(JSON.parse(atob(document.getElementById('remoteSessionDescription').value)))).catch(log)
pc.createAnswer().then(d => pc.setLocalDescription(d)).catch(log)
}
// websockets
var socket;
const socketMessageListener = (event) => {
log(event);
log(event.data);
var data = JSON.parse(event.data);
console.log(data);
};
var blob = file.slice(start, stop + 1);
reader.readAsBinaryString(blob);
}
document.querySelector('.readBytesButtons').addEventListener('click', function(evt) {
if (evt.target.tagName.toLowerCase() == 'button') {
var startByte = evt.target.getAttribute('data-startbyte');
var endByte = evt.target.getAttribute('data-endbyte');
readBlob(startByte, endByte);
const socketOpenListener = (event) => {
log('connected to websockets');
socket.send(JSON.stringify({
"Message": "offerer",
}))
}
}, false);
let pc = new RTCPeerConnection({
iceServers: [{
urls: 'stun:stun.l.google.com:19302'
}]
})
let log = msg => {
console.log(msg);
}
pc.onsignalingstatechange = e => log(pc.signalingState)
pc.oniceconnectionstatechange = e => log(pc.iceConnectionState)
pc.onicecandidate = event => {
if (event.candidate === null) {
log(JSON.stringify(pc.localDescription))
}
}
pc.ondatachannel = e => {
let dc = e.channel
log('New DataChannel ' + dc.label)
dc.onclose = () => log('dc has closed')
dc.onopen = () => {
log('dc has opened');
}
dc.onmessage = e => {
log(`Message from DataChannel '${dc.label}' payload '${e.data}'`)
}
window.sendMessage = e => {
let message = e;
if (message === '') {
return alert('Message must not be empty')
const socketCloseListener = (event) => {
if (socket) {
log('Disconnected.');
}
dc.send(message)
}
}
window.startSession = () => {
pc.setRemoteDescription(new RTCSessionDescription(JSON.parse(atob(document.getElementById('remoteSessionDescription').value)))).catch(log)
pc.createAnswer().then(d => pc.setLocalDescription(d)).catch(log)
}
// websockets
var socket;
const socketMessageListener = (event) => {
log(event);
};
const socketOpenListener = (event) => {
log('Connected');
}
const socketCloseListener = (event) => {
if (socket) {
log('Disconnected.');
}
// var ws_url = window.origin.replace("http", "ws") + '/ws/test1';
var ws_url = "ws://localhost:8005/ws/test1";
log(`connecting to '${ws_url}'`)
socket = new WebSocket(ws_url);
socket.addEventListener('open', socketOpenListener);
socket.addEventListener('message', socketMessageListener);
socket.addEventListener('close', socketCloseListener);
};
socketCloseListener();
// var ws_url = window.origin.replace("http", "ws") + '/ws/test1';
var ws_url = "ws://localhost:8005/ws/test1";
log(`connecting to '${ws_url}'`)
socket = new WebSocket(ws_url);
socket.addEventListener('open', socketOpenListener);
socket.addEventListener('message', socketMessageListener);
socket.addEventListener('close', socketCloseListener);
};
socketCloseListener();
</script>
<script src="wasm_exec.js"></script>
<script>
const go = new Go();
WebAssembly.instantiateStreaming(fetch("main.wasm"), go.importObject).then((result) => {
go.run(result.instance);
});
const go = new Go();
WebAssembly.instantiateStreaming(fetch("main.wasm"), go.importObject).then((result) => {
go.run(result.instance);
});
</script>
</body>