first commit

This commit is contained in:
encrypt 2016-11-24 16:16:36 +01:00
commit e1cbaed324
7 changed files with 327 additions and 0 deletions

1
.gitignore vendored Normal file
View file

@ -0,0 +1 @@
*~

100
client/crypto.js Normal file
View file

@ -0,0 +1,100 @@
var CryptoUtils = {
cypher: "AES-GCM",
key: null,
iv: null,
urlSafeKey: null,
urlSafeIV: null,
initialize: function(key = null, iv = null) {
if(key === null || iv === null) {
this.generateIV();
return this.generateKey();
}
else {
this.iv = this.base64ToArrayBuffer(iv)
this.urlSafeIV = iv;
this.urlSafeKey = key;
return this.importKey(this.base64ToArrayBuffer(key));
}
},
generateKey: function() {
var self = this;
return window.crypto.subtle.generateKey(
{
name: this.cypher,
length: 256,
},
true,
["encrypt", "decrypt"]
).then(function(k){
self.key = k;
return window.crypto.subtle.exportKey("raw", k)
}).then(function(keydata) {
console.log(keydata);
self.urlSafeKey = self.arrayBufferToBase64(keydata);
}).catch(function(err){
console.error(err)
});
},
generateIV: function() {
this.iv = window.crypto.getRandomValues(new Uint8Array(12));
this.urlSafeIV = this.arrayBufferToBase64(this.iv);
},
encrypt: function(data) {
return window.crypto.subtle.encrypt(
{
name: this.cypher,
iv: this.iv,
},
this.key,
data
);
},
decrypt: function(data) {
return window.crypto.subtle.decrypt(
{
name: this.cypher,
iv: this.iv,
},
this.key,
data
);
},
importKey: function(key) {
var self = this;
return window.crypto.subtle.importKey(
"raw",
key,
{
name: self.cypher
},
true,
["encrypt", "decrypt"]
).then(function(k){
self.key = k;
});
},
importIV: function(iv) {
},
arrayBufferToBase64: function(a) {
return btoa(String.fromCharCode(...new Uint8Array(a)))
},
base64ToArrayBuffer: function(b) {
var str = atob(b);
var buf = new ArrayBuffer(str.length);
var bufView = new Uint8Array(buf);
for (var i=0, strLen=str.length; i<strLen; i++) {
bufView[i] = str.charCodeAt(i);
}
return buf;
}
}

26
client/index.html Normal file
View file

@ -0,0 +1,26 @@
<html>
<head>
<script src="vendor/zepto.min.js"></script>
<script src="crypto.js"></script>
<script src="main.js"></script>
</head>
<body>
<div id="create-room">
<input type="button" value="create room">
</div>
<div id="room">
<div id="link">
</div>
<div id="upload">
<form>
<input id="file-selector" type="file" name="file"/>
<input id="woot" type="button" name="upload" value="upload"/>
</form>
</div>
<div id="file-list">
<ul>
</ul>
</div>
</div>
</body>
</html>

145
client/main.js Normal file
View file

@ -0,0 +1,145 @@
var Uploader = {
roomId: null,
createRoom: function() {
var self = this;
$.post('/room', {}, function(response) {
self.roomId = $.parseJSON(response).id
})
},
getRoom: function(callback) {
$.getJSON('/room/'+this.roomId, callback)
},
getFile: function(fileName, callback) {
var xhr = new XMLHttpRequest();
xhr.open('GET', '/room/'+this.roomId+'/'+fileName, true);
xhr.responseType = 'arraybuffer';
xhr.onload = callback;
xhr.send();
},
deleteRoom: function() {
$.ajax({
type: 'DELETE',
url: '/room/'+this.roomId
})
},
uploadFile: function(name, data){
var formData = new FormData();
formData.append("file", data, name);
$.ajax({
url: '/room/'+this.roomId,
data: formData,
cache: false,
processData: false,
contentType: false,
xhr: function () {
var xhr = new XMLHttpRequest()
//xhr.upload.addEventListener('progress', progress, false)
return xhr
},
type: 'POST'
});
},
deleteFile: function() {
console.log('NOPE');
},
}
var CryptoUploader = {
createRoom: function() {
Uploader.createRoom();
CryptoUtils.initialize().then(function(){
window.location = window.location.href+"#"+Uploader.roomId+","+CryptoUtils.urlSafeKey+","+CryptoUtils.urlSafeIV;
window.location.reload();
})
},
uploadFile: function() {
var fileReader = new FileReader();
var data;
var file = document.getElementById("file-selector").files[0];
var self = this;
fileReader.onload = function(e) {
this.data = fileReader.result;
CryptoUtils.encrypt(this.data)
.then(function(encrypted){
Uploader.uploadFile(file.name, new Blob([encrypted], { type: 'application/octet-binary' }));
self.showRoomContent();
}).catch(function(err){
console.error(err);
});
};
fileReader.readAsArrayBuffer(file);
},
downloadFile: function(fileName) {
Uploader.getFile(fileName, function(e){
if(this.status == 200) {
CryptoUtils.decrypt(this.response).
then(function(decrypted){
var a = document.createElement("a");
document.body.appendChild(a);
a.style = "display: none";
blob = new Blob([decrypted], {type: "application/octet-binary"}),
url = window.URL.createObjectURL(blob);
a.href = url;
a.download = fileName;
a.click();
window.URL.revokeObjectURL(url);
}).catch(function(err){
console.error(err);
})
}
})
},
showRoomContent: function() {
$("#file-list > ul").empty();
Uploader.getRoom(function(data){
for(let f of data.entries()) {
//var a = document.createElement("a");
$("<li><a>"+f[1]+"</a></li>")
.appendTo("#file-list > ul")
.on('click', function(e){CryptoUploader.downloadFile(e.target.text)});
}
})
}
}
$(function(){
if(window.location.hash) {
var params = window.location.hash.substr(1).split(',');
var roomId = params.shift();
var key = params.shift();
var iv = params.shift();
var file = params.shift();
$("#create-room").hide();
$("#room").show();
Uploader.roomId = roomId;
CryptoUtils.initialize(key, iv).then(function(){
$("#woot").on('click', function(){
CryptoUploader.uploadFile();
});
CryptoUploader.showRoomContent();
if(file !== undefined) {
CryptoUploader.downloadFile(file);
}
}).catch(function(err){
console.error(err);
});
}
else {
$("#room").hide();
$("#create-room").show();
$("#create-room > input").on('click', function(e){
CryptoUploader.createRoom();
});
}
})

2
client/vendor/zepto.min.js vendored Normal file

File diff suppressed because one or more lines are too long

1
server/public Symbolic link
View file

@ -0,0 +1 @@
/home/marco/projects/bohbohboh/client/

52
server/server.rb Normal file
View file

@ -0,0 +1,52 @@
require 'sinatra'
require 'securerandom'
require 'json'
# create a room
post '/room' do
id = SecureRandom.hex(4)
Dir.mkdir(id)
content_type 'text/json'
{id: id}.to_json
end
# get room content
get '/room/:id' do |id|
if Dir.exist?('./'+id)
content_type 'text/json'
Dir.glob('./'+id+'/*').map { |f| File.basename(f)}.to_json
else
404
end
end
# upload a file
post '/room/:id' do |id|
unless params[:file] &&
(tmpfile = params[:file][:tempfile]) &&
(name = params[:file][:filename])
403
return
end
FileUtils.cp(tmpfile, "./"+id+"/"+name)
200
end
# remove a room
delete '/room/:id' do |id|
end
# get a file
get '/room/:id/:filename' do |id, filename|
send_file File.join('./'+id, filename)
end
# remove a file
delete '/room/:id/:filename' do |id, filename|
end