new branch
This commit is contained in:
parent
0782cef593
commit
a45bcf3d35
13
README.md
13
README.md
|
@ -1,10 +1,3 @@
|
|||
* Make sure you have a redis server running: download redis using homebrew: brew install redis
|
||||
* Start the redis server: redis-server /usr/local/etc/redis.conf
|
||||
* To run the code, clone the git repo, cd into the folder, and run npm install. Then, run npm start.
|
||||
|
||||
Steps to start exchanging messages:
|
||||
|
||||
* Open two separate tabs, one with a location hash of #init. For example, if the port being used is 3000, open one tab as http://localhost:3000/#init, and one as http://localhost:3000.
|
||||
* The tab with the location hash should have a button that says create channel. Click that button, and wait for an alert dialog to pop up (this might take a while).
|
||||
* In the tab without the init hash, paste the generated code in the input field with the join channel placeholder text.
|
||||
* Click connect in the tab without the init hash. Then, click connect in the tab with the init hash (order shouldn't actually matter). You should be able to send messages and see them in the other tab now.
|
||||
* Install the redis server if not installed.
|
||||
* To run the project, make sure you have a redis server running locally: redis-server /usr/local/etc/redis.conf
|
||||
* Follow instructions inside the console on the browser.
|
||||
|
|
100
app.js
100
app.js
|
@ -1,5 +1,7 @@
|
|||
const express = require('express')
|
||||
const bodyParser = require('body-parser')
|
||||
var busboy = require('connect-busboy'); //middleware for form/file upload
|
||||
var path = require('path'); //used for file path
|
||||
var fs = require('fs-extra'); //File System - for file manipulation
|
||||
const app = express()
|
||||
var redis = require("redis"),
|
||||
client = redis.createClient();
|
||||
|
@ -8,76 +10,58 @@ client.on('error', function(err) {
|
|||
console.log(err);
|
||||
})
|
||||
|
||||
app.use(bodyParser.json());
|
||||
app.use(busboy());
|
||||
app.use(express.static(path.join(__dirname, 'public')));
|
||||
|
||||
app.use(express.static('public'))
|
||||
|
||||
app.use(function(req, res, next) {
|
||||
res.header("Access-Control-Allow-Origin", "*");
|
||||
res.header("Access-Control-Allow-Headers", "Origin, X-Requested-With, Content-Type, Accept");
|
||||
next();
|
||||
});
|
||||
|
||||
function insert(create_key) {
|
||||
let id = Math.floor(Math.random()*10000).toString();
|
||||
client.set(id, create_key, redis.print);
|
||||
return id;
|
||||
}
|
||||
|
||||
app.post('/local_answer/:id', function(req, res) {
|
||||
let id = req.params.id;
|
||||
client.set(id, JSON.stringify(req.body), redis.print);
|
||||
res.send('ok');
|
||||
app.get('/', function (req, res) {
|
||||
res.send('Hello World!')
|
||||
})
|
||||
|
||||
app.get('/receive_offer/:id', function(req, res) {
|
||||
app.get('/download/:id', function(req, res) {
|
||||
res.sendFile(path.join(__dirname + '/public/download.html'));
|
||||
});
|
||||
|
||||
app.get('/assets/download/:id', function(req, res) {
|
||||
|
||||
let id = req.params.id;
|
||||
client.get(id, function(err, reply) {
|
||||
client.hget(id, "filename", function(err, reply) { // maybe some expiration logic too
|
||||
if (!reply) {
|
||||
res.send('error');
|
||||
} else {
|
||||
res.send(reply);
|
||||
res.setHeader('Content-Disposition', 'attachment; filename=' + reply);
|
||||
// res.setHeader('Content-Transfer-Encoding', 'binary');
|
||||
res.setHeader('Content-Type', 'application/octet-stream');
|
||||
|
||||
res.download(__dirname + '/static/' + reply);
|
||||
}
|
||||
})
|
||||
})
|
||||
|
||||
});
|
||||
|
||||
app.route('/upload')
|
||||
.post(function (req, res, next) {
|
||||
|
||||
var fstream;
|
||||
req.pipe(req.busboy);
|
||||
req.busboy.on('file', function (fieldname, file, filename) {
|
||||
console.log("Uploading: " + filename);
|
||||
|
||||
//Path where image will be uploaded
|
||||
fstream = fs.createWriteStream(__dirname + '/static/' + filename);
|
||||
file.pipe(fstream);
|
||||
fstream.on('close', function () {
|
||||
let id = Math.floor(Math.random()*10000).toString();
|
||||
client.hset(id, "filename", filename, redis.print);
|
||||
client.hset(id, "expiration", 0, redis.print);
|
||||
console.log("Upload Finished of " + filename);
|
||||
res.send(id); //where to go next
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
app.get('/receive_answer/:id', function(req, res) {
|
||||
let id = req.params.id;
|
||||
client.get(id, function(err, reply) {
|
||||
if (!reply) {
|
||||
res.send('error');
|
||||
} else {
|
||||
client.del(id);
|
||||
res.send(reply);
|
||||
}
|
||||
})
|
||||
})
|
||||
|
||||
app.post('/join/:id', function(req, res) {
|
||||
let id = req.params.id;
|
||||
client.get(id, function(err, reply) {
|
||||
if (!reply) {
|
||||
res.send('error')
|
||||
} else {
|
||||
res.send(reply);
|
||||
}
|
||||
})
|
||||
})
|
||||
|
||||
app.post('/create', function(req, res) {
|
||||
let id = insert(JSON.stringify(req.body));
|
||||
res.send(id);
|
||||
})
|
||||
|
||||
|
||||
app.get('/', function (req, res) {
|
||||
console.log('get');
|
||||
res.send('Hello World!')
|
||||
})
|
||||
|
||||
app.listen(3000, function () {
|
||||
console.log('Example app listening on port 3000!')
|
||||
})
|
||||
|
||||
|
||||
|
|
19
package.json
19
package.json
|
@ -1,19 +1,18 @@
|
|||
{
|
||||
"name": "portal-alpha",
|
||||
"version": "0.1.0",
|
||||
"version": "1.0.0",
|
||||
"description": "",
|
||||
"scripts": {
|
||||
"start": "browserify public/index.js -o public/bundle.js & node app.js"
|
||||
"test": "echo \"Error: no test specified\" && exit 1",
|
||||
"start": "node app.js"
|
||||
},
|
||||
"license": "MIT",
|
||||
"author": "",
|
||||
"license": "ISC",
|
||||
"dependencies": {
|
||||
"body-parser": "^1.17.2",
|
||||
"connect-busboy": "0.0.2",
|
||||
"express": "^4.15.3",
|
||||
"redis": "^2.7.1",
|
||||
"simple-peer": "^5.11.4",
|
||||
"wrtc": "0.0.62"
|
||||
},
|
||||
"devDependencies": {
|
||||
"browserify": "^14.3.0"
|
||||
"fs-extra": "^3.0.1",
|
||||
"path": "^0.12.7",
|
||||
"redis": "^2.7.1"
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,18 @@
|
|||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<title>Page Title</title>
|
||||
<script type="text/javascript" src="/file.js"></script>
|
||||
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<input id="keyhash" placeholder="Paste the key your friend sent you."/><br />
|
||||
<input id="salt" placeholder="Paste the salt your friend sent you."/><br />
|
||||
|
||||
<button onclick="download()">DOWNLOAD</button>
|
||||
|
||||
|
||||
|
||||
</body>
|
||||
</html>
|
|
@ -0,0 +1,160 @@
|
|||
function download() {
|
||||
var xhr = new XMLHttpRequest();
|
||||
xhr.open('get', '/assets' + location.pathname, true);
|
||||
xhr.responseType = 'blob';
|
||||
// $.each(SERVER.authorization(), function(k, v) {
|
||||
// xhr.setRequestHeader(k, v);
|
||||
// });
|
||||
// xhr.setRequestHeader('Content-type', 'application/json; charset=utf-8');
|
||||
|
||||
xhr.onload = function(e) {
|
||||
if (this.status == 200) {
|
||||
let self = this;
|
||||
var blob = new Blob([this.response]);
|
||||
var arrayBuffer;
|
||||
var fileReader = new FileReader();
|
||||
fileReader.onload = function() {
|
||||
arrayBuffer = this.result;
|
||||
// console.log(arrayBuffer);
|
||||
var array = new Uint8Array(arrayBuffer);
|
||||
salt = new Uint8Array(JSON.parse(document.getElementById('salt').value));
|
||||
window.crypto.subtle.importKey(
|
||||
"jwk", //can be "jwk" or "raw"
|
||||
{ //this is an example jwk key, "raw" would be an ArrayBuffer
|
||||
kty: "oct",
|
||||
k: document.getElementById('keyhash').value,
|
||||
alg: "A128CBC",
|
||||
ext: true,
|
||||
},
|
||||
{ //this is the algorithm options
|
||||
name: "AES-CBC",
|
||||
},
|
||||
true, //whether the key is extractable (i.e. can be used in exportKey)
|
||||
["encrypt", "decrypt"] //can be "encrypt", "decrypt", "wrapKey", or "unwrapKey"
|
||||
)
|
||||
.then(function(key){
|
||||
//returns the symmetric key
|
||||
window.crypto.subtle.decrypt(
|
||||
{
|
||||
name: "AES-CBC",
|
||||
iv: salt, //The initialization vector you used to encrypt
|
||||
},
|
||||
key, //from generateKey or importKey above
|
||||
array //ArrayBuffer of the data
|
||||
)
|
||||
.then(function(decrypted){
|
||||
//returns an ArrayBuffer containing the decrypted data
|
||||
// let original = new Uint8Array(decrypted);
|
||||
var dataView = new DataView(decrypted);
|
||||
var blob = new Blob([dataView]);
|
||||
var downloadUrl = URL.createObjectURL(blob);
|
||||
var a = document.createElement("a");
|
||||
a.href = downloadUrl;
|
||||
a.download = xhr.getResponseHeader('Content-Disposition').match(/filename="(.+)"/)[1];;
|
||||
document.body.appendChild(a);
|
||||
a.click();
|
||||
})
|
||||
.catch(function(err){
|
||||
console.error(err);
|
||||
});
|
||||
// console.log(key);
|
||||
})
|
||||
.catch(function(err){
|
||||
console.error(err);
|
||||
});
|
||||
};
|
||||
fileReader.readAsArrayBuffer(blob);
|
||||
// console.log(blob);
|
||||
// var downloadUrl = URL.createObjectURL(blob);
|
||||
// var a = document.createElement("a");
|
||||
// a.href = downloadUrl;
|
||||
// // a.download = "feheroes.png";
|
||||
// document.body.appendChild(a);
|
||||
// a.click();
|
||||
} else {
|
||||
alert('Unable to download excel.')
|
||||
}
|
||||
};
|
||||
xhr.send();
|
||||
}
|
||||
|
||||
function onChange(event) {
|
||||
var file = event.target.files[0];
|
||||
var reader = new FileReader();
|
||||
reader.onload = function(event) {
|
||||
// The file's text will be printed here
|
||||
let self = this;
|
||||
window.crypto.subtle.generateKey({
|
||||
name: "AES-CBC",
|
||||
length: 128
|
||||
},
|
||||
true, //whether the key is extractable (i.e. can be used in exportKey)
|
||||
["encrypt", "decrypt"])
|
||||
.then(function(key){
|
||||
//returns a key object
|
||||
var arrayBuffer = self.result;
|
||||
var array = new Uint8Array(arrayBuffer);
|
||||
// binaryString = String.fromCharCode.apply(null, array);
|
||||
|
||||
// console.log(binaryString);
|
||||
// console.log(file);
|
||||
|
||||
var random_iv = window.crypto.getRandomValues(new Uint8Array(16));
|
||||
|
||||
window.crypto.subtle.encrypt({
|
||||
name: "AES-CBC",
|
||||
//Don't re-use initialization vectors!
|
||||
//Always generate a new iv every time your encrypt!
|
||||
iv: random_iv},
|
||||
key, //from generateKey or importKey above
|
||||
array //ArrayBuffer of data you want to encrypt
|
||||
)
|
||||
.then(function(encrypted){
|
||||
console.log('Send this salt to a friend: [' + random_iv.toString() + ']');
|
||||
// console.log(arrayBuffer);
|
||||
//returns an ArrayBuffer containing the encrypted data
|
||||
var dataView = new DataView(encrypted);
|
||||
var blob = new Blob([dataView], { type: file.type });
|
||||
window.data = encrypted;
|
||||
var fd = new FormData();
|
||||
fd.append('fname', file.name);
|
||||
fd.append('data', blob, file.name);
|
||||
// console.log(blob);
|
||||
var xhr = new XMLHttpRequest();
|
||||
|
||||
xhr.open('post', '/upload', true);
|
||||
xhr.onreadystatechange = function() {
|
||||
if (xhr.readyState == XMLHttpRequest.DONE) {
|
||||
console.log('Go to this URL: http://localhost:3000/download/'+xhr.responseText);
|
||||
}
|
||||
};
|
||||
|
||||
xhr.send(fd);
|
||||
})
|
||||
.catch(function(err){
|
||||
console.error(err);
|
||||
});
|
||||
|
||||
|
||||
window.crypto.subtle.exportKey(
|
||||
"jwk", //can be "jwk" or "raw"
|
||||
key)
|
||||
.then(function(keydata){
|
||||
//returns the exported key data
|
||||
console.log('Send this key to a friend: ' + keydata.k);
|
||||
|
||||
})
|
||||
.catch(function(err){
|
||||
console.error(err);
|
||||
});
|
||||
})
|
||||
.catch(function(err){
|
||||
console.error(err);
|
||||
});
|
||||
|
||||
|
||||
};
|
||||
|
||||
reader.readAsArrayBuffer(file);
|
||||
}
|
||||
|
|
@ -1,25 +1,18 @@
|
|||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title></title>
|
||||
</head>
|
||||
<body>
|
||||
<head>
|
||||
<title>Page Title</title>
|
||||
<script src="file.js"></script>
|
||||
|
||||
<!--<label>Your ID:</label><br/>-->
|
||||
<button id="createChannel">Create a new channel</button>
|
||||
<input id="joinChannel" placeholder="Join a channel"></input>
|
||||
<textarea id="yourId" style="display: none"></textarea><br/>
|
||||
<!--<label>Other ID:</label><br/>-->
|
||||
<textarea id="otherId" style="display: none"></textarea>
|
||||
<button id="connect">connect</button><br/>
|
||||
<br /> <br />
|
||||
<label>Enter Message:</label><br/>
|
||||
<textarea id="yourMessage"></textarea>
|
||||
<button id="send">send</button>
|
||||
<pre id="messages"></pre>
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<script src="bundle.js" charset="utf-8"></script>
|
||||
</body>
|
||||
</html>
|
||||
<form method='post' action='upload' enctype="multipart/form-data">
|
||||
<input type='file' onchange="onChange(event)" name='fileUploaded' />
|
||||
</form>
|
||||
|
||||
|
||||
|
||||
|
||||
</body>
|
||||
</html>
|
||||
|
|
126
public/index.js
126
public/index.js
|
@ -1,126 +0,0 @@
|
|||
// TODO: delete id's out of redis server
|
||||
// TODO: make sure random id generated is not already in use
|
||||
|
||||
const Peer = require('simple-peer');
|
||||
|
||||
var peer;
|
||||
var id = 0;
|
||||
|
||||
if (location.hash === "#init") {
|
||||
document.getElementById('joinChannel').style = "display: none";
|
||||
document.getElementById('createChannel').addEventListener('click', function() {
|
||||
peer = new Peer({
|
||||
initiator: location.hash === "#init",
|
||||
trickle: false
|
||||
});
|
||||
|
||||
do_connection();
|
||||
})
|
||||
} else {
|
||||
document.getElementById('createChannel').style = "display: none";
|
||||
peer = new Peer({
|
||||
initiator: location.hash === "#init",
|
||||
trickle: false
|
||||
});
|
||||
|
||||
do_connection();
|
||||
}
|
||||
|
||||
|
||||
|
||||
function do_connection() {
|
||||
|
||||
peer.on('signal', function(data) {
|
||||
if (peer.initiator) {
|
||||
var xmlhttp = new XMLHttpRequest(); // new HttpRequest instance
|
||||
xmlhttp.open("POST", "http://127.0.0.1:3000/create");
|
||||
xmlhttp.setRequestHeader("Content-Type", "application/json");
|
||||
xmlhttp.send(JSON.stringify(data));
|
||||
xmlhttp.onreadystatechange = function() {
|
||||
if (xmlhttp.readyState === 4) {
|
||||
id = xmlhttp.responseText;
|
||||
alert('Share this key with a friend: ' + id);
|
||||
document.getElementById('yourId').value = JSON.stringify(data);
|
||||
// alert('Send this id to someone else to join your room: ' + xmlhttp.responseText); //Outputs a DOMString by default
|
||||
}
|
||||
}
|
||||
} else {
|
||||
document.getElementById('yourId').value = JSON.stringify(data);
|
||||
|
||||
var xmlhttp = new XMLHttpRequest(); // new HttpRequest instance
|
||||
xmlhttp.open("POST", "http://127.0.0.1:3000/local_answer/" + id + "_answer");
|
||||
xmlhttp.setRequestHeader("Content-Type", "application/json");
|
||||
xmlhttp.send(JSON.stringify(data));
|
||||
xmlhttp.onreadystatechange = function() {
|
||||
if (xmlhttp.readyState === 4) {
|
||||
// id = xmlhttp.responseText;
|
||||
// document.getElementById('yourId').value = xmlhttp.responseText;
|
||||
// alert('Send this id to someone else to join your room: ' + xmlhttp.responseText); //Outputs a DOMString by default
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
document.getElementById('connect').addEventListener('click', function() {
|
||||
if (!peer.initiator) {
|
||||
let otherId = document.getElementById('joinChannel').value;
|
||||
id = otherId;
|
||||
var xmlhttp = new XMLHttpRequest(); // new HttpRequest instance
|
||||
xmlhttp.open("GET", "http://127.0.0.1:3000/receive_offer/"+otherId);
|
||||
xmlhttp.send();
|
||||
xmlhttp.onreadystatechange = function() {
|
||||
if (xmlhttp.readyState === 4) {
|
||||
document.getElementById('otherId').value = xmlhttp.responseText;
|
||||
peer.signal(xmlhttp.responseText);
|
||||
// alert('Send this id to someone else to join your room: ' + xmlhttp.responseText); //Outputs a DOMString by default
|
||||
}
|
||||
}
|
||||
} else {
|
||||
poll_on_server();
|
||||
// let otherId = JSON.parse(document.getElementById('otherId').value);
|
||||
// peer.signal(otherId);
|
||||
}
|
||||
|
||||
function poll_on_server() {
|
||||
var xmlhttp = new XMLHttpRequest(); // new HttpRequest instance
|
||||
xmlhttp.open("GET", "http://127.0.0.1:3000/receive_answer/" + id + "_answer");
|
||||
xmlhttp.send();
|
||||
xmlhttp.onreadystatechange = function() {
|
||||
if (xmlhttp.readyState === 4) {
|
||||
// var offerDesc = new RTCSessionDescription(JSON.parse(xmlhttp.responseText))
|
||||
if (xmlhttp.responseText === document.getElementById('yourId').value) {
|
||||
setTimeout(poll_on_server, 5000);
|
||||
} else {
|
||||
document.getElementById('otherId').value = xmlhttp.responseText;
|
||||
let otherId = JSON.parse(document.getElementById('otherId').value);
|
||||
peer.signal(otherId);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// id = otherId;
|
||||
// var xmlhttp = new XMLHttpRequest(); // new HttpRequest instance
|
||||
// xmlhttp.open("GET", "http://127.0.0.1:3000/receive_offer/"+id);
|
||||
// xmlhttp.send();
|
||||
// xmlhttp.onreadystatechange = function() {
|
||||
// if (xmlhttp.readyState === 4) {
|
||||
// id = xmlhttp.responseText;
|
||||
// document.getElementById('otherId').value = xmlhttp.responseText;
|
||||
|
||||
// peer.signal(JSON.parse(xmlhttp.responseText));
|
||||
// // alert('Send this id to someone else to join your room: ' + xmlhttp.responseText); //Outputs a DOMString by default
|
||||
// }
|
||||
// }
|
||||
});
|
||||
|
||||
document.getElementById('send').addEventListener('click', function() {
|
||||
let yourMessage = document.getElementById('yourMessage').value;
|
||||
peer.send(yourMessage);
|
||||
});
|
||||
|
||||
peer.on('data', function(data) {
|
||||
document.getElementById('messages').textContent += data + '\n';
|
||||
});
|
||||
|
||||
}
|
|
@ -0,0 +1 @@
|
|||
This is where files will go.
|
Loading…
Reference in New Issue