|
|
|
@ -37,6 +37,11 @@ |
|
|
|
|
// 1 2 3 4 5 6 7 8
|
|
|
|
|
// 45678901234567890123456789012345678901234567890123456789012345678901234567890
|
|
|
|
|
|
|
|
|
|
function log() { |
|
|
|
|
//[].push.call(arguments, (new Error()).stack)
|
|
|
|
|
console.log.apply(null, arguments) |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
function SafeChat() { |
|
|
|
|
|
|
|
|
|
/// Create UID from a name by appending an E-Mail
|
|
|
|
@ -105,9 +110,9 @@ function SafeChat() { |
|
|
|
|
|
|
|
|
|
//------------------------------------------------------------------------------
|
|
|
|
|
if (openpgp.initWorker("openpgp.worker.min.js")) |
|
|
|
|
console.log("asynchronous openpgp enabled") |
|
|
|
|
log("asynchronous openpgp enabled") |
|
|
|
|
else |
|
|
|
|
console.log("asynchronous openpgp failed") |
|
|
|
|
log("asynchronous openpgp failed") |
|
|
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
@ -156,16 +161,19 @@ function SafeChat() { |
|
|
|
|
var socket = io.connect() |
|
|
|
|
|
|
|
|
|
function broadcast(signal, data) { |
|
|
|
|
console.log("<=snd "+signal) |
|
|
|
|
log(' function broadcast(signal, data)') |
|
|
|
|
log("<=snd "+signal) |
|
|
|
|
socket.broadcast.emit(signal, data) |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
function emit(signal, data, next) { |
|
|
|
|
console.log("<-snd "+signal) |
|
|
|
|
log(' function emit(signal, data, next)') |
|
|
|
|
log("<-snd "+signal) |
|
|
|
|
socket.emit(signal, data, next) |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
this.lookup = function(usr, next) { |
|
|
|
|
log(' this.lookup = function(usr, next)') |
|
|
|
|
emit('user', usr, next) |
|
|
|
|
} |
|
|
|
|
|
|
|
|
@ -198,22 +206,26 @@ function SafeChat() { |
|
|
|
|
|
|
|
|
|
/// Padding for numbers in dates
|
|
|
|
|
function pad(n) { |
|
|
|
|
log(' function pad(n)') |
|
|
|
|
return n<10 ? '0'+n : n |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/// escape text to show in html @see htmldec
|
|
|
|
|
function htmlenc(html) { |
|
|
|
|
log(' function htmlenc(html)') |
|
|
|
|
return $('<div/>').text(html).html() |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/// decode html encoded text @see htmlenc
|
|
|
|
|
function htmldec(data) { |
|
|
|
|
log(' function htmldec(data)') |
|
|
|
|
return $('<div/>').html(data).text() |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/// alert user accoustically or by vibration
|
|
|
|
|
/** alert user, e.g. that a new message has arrived. */ |
|
|
|
|
function beep() { |
|
|
|
|
log(' function beep()') |
|
|
|
|
if (navigator.vibrate) navigator.vibrate(1000) |
|
|
|
|
(new Audio("sounds/beep.mp3")).play() |
|
|
|
|
} |
|
|
|
@ -222,6 +234,7 @@ function SafeChat() { |
|
|
|
|
/** something completely failed, abort |
|
|
|
|
@param msg */ |
|
|
|
|
function fatal(msg) { |
|
|
|
|
log(' function fatal(msg)') |
|
|
|
|
if (nexttimer) clearTimeout(nexttimer) |
|
|
|
|
if (msg) { |
|
|
|
|
error(msg) |
|
|
|
@ -236,6 +249,7 @@ function SafeChat() { |
|
|
|
|
Strings are shown to the user, structures are logged only. |
|
|
|
|
@param next (optional) next function to call */ |
|
|
|
|
function error(data, next) { |
|
|
|
|
log(' function error(data, next)') |
|
|
|
|
if (nexttimer) clearTimeout(nexttimer) |
|
|
|
|
$("#status").hide() |
|
|
|
|
$("#status").addClass("error") |
|
|
|
@ -244,14 +258,14 @@ function SafeChat() { |
|
|
|
|
if (data) { |
|
|
|
|
if (typeof data == 'string') { |
|
|
|
|
$("#status").html(data) |
|
|
|
|
console.log("error: "+data) |
|
|
|
|
log("error: "+data) |
|
|
|
|
} else { |
|
|
|
|
$("#status").html('error') |
|
|
|
|
console.log("error: "+JSON.stringify(data)) |
|
|
|
|
log("error: "+JSON.stringify(data)) |
|
|
|
|
} |
|
|
|
|
} else { |
|
|
|
|
$("#status").html('error') |
|
|
|
|
console.log("error") |
|
|
|
|
log("error") |
|
|
|
|
} |
|
|
|
|
$("#status").show() |
|
|
|
|
if (next) nexttimer = setTimeout(function() { |
|
|
|
@ -264,16 +278,17 @@ function SafeChat() { |
|
|
|
|
/** shows an notice message and logs to console. |
|
|
|
|
@param text (optional) The data is a string. */ |
|
|
|
|
function notice(text) { |
|
|
|
|
log(' function notice(text)') |
|
|
|
|
$("#status").hide() |
|
|
|
|
$("#status").addClass("notice") |
|
|
|
|
$("#status").removeClass("error") |
|
|
|
|
$("#status").removeClass("success") |
|
|
|
|
if (text) { |
|
|
|
|
$("#status").html(text) |
|
|
|
|
console.log("notice: "+text) |
|
|
|
|
log("notice: "+text) |
|
|
|
|
} else { |
|
|
|
|
$("#status").html('') |
|
|
|
|
console.log("notice") |
|
|
|
|
log("notice") |
|
|
|
|
} |
|
|
|
|
$("#status").show() |
|
|
|
|
} |
|
|
|
@ -282,16 +297,17 @@ function SafeChat() { |
|
|
|
|
/** shows an success message and logs to console. |
|
|
|
|
@param text (optional) The data is a string. */ |
|
|
|
|
function success(text) { |
|
|
|
|
log(' function success(text)') |
|
|
|
|
$("#status").hide() |
|
|
|
|
$("#status").addClass("success") |
|
|
|
|
$("#status").removeClass("error") |
|
|
|
|
$("#status").removeClass("notice") |
|
|
|
|
if (text) { |
|
|
|
|
$("#status").html(text) |
|
|
|
|
console.log("success: "+text) |
|
|
|
|
log("success: "+text) |
|
|
|
|
} else { |
|
|
|
|
$("#status").html('') |
|
|
|
|
console.log("success") |
|
|
|
|
log("success") |
|
|
|
|
} |
|
|
|
|
$("#status").show() |
|
|
|
|
} |
|
|
|
@ -300,7 +316,8 @@ function SafeChat() { |
|
|
|
|
/** @param id html id to be shown. |
|
|
|
|
@param msg (optional) the success message text */ |
|
|
|
|
function show(id, msg) { |
|
|
|
|
console.log("state: "+id) |
|
|
|
|
log(' function show(id, msg)') |
|
|
|
|
log("state: "+id) |
|
|
|
|
if (msg) success(msg); else $("#status").hide(); |
|
|
|
|
$("#main").children(":not(#"+id+")").hide() |
|
|
|
|
$("#main #"+id).show() |
|
|
|
@ -309,7 +326,8 @@ function SafeChat() { |
|
|
|
|
|
|
|
|
|
/// show server connected status
|
|
|
|
|
function connected() { |
|
|
|
|
console.log("server connected") |
|
|
|
|
log(' function connected()') |
|
|
|
|
log("server connected") |
|
|
|
|
$("#connectionstatus #bad").hide() |
|
|
|
|
$("#connectionstatus #good").show() |
|
|
|
|
success("server connected") |
|
|
|
@ -317,18 +335,21 @@ function SafeChat() { |
|
|
|
|
|
|
|
|
|
/// show server disconnected status
|
|
|
|
|
function disconnected() { |
|
|
|
|
console.log("server disconnected") |
|
|
|
|
log(' function disconnected()') |
|
|
|
|
log("server disconnected") |
|
|
|
|
$("#connectionstatus #good").hide() |
|
|
|
|
$("#connectionstatus #bad").show() |
|
|
|
|
error("server disconnected", true) |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/// toggle menu display
|
|
|
|
|
function togglemenu() { |
|
|
|
|
this.togglemenu = function() { |
|
|
|
|
log(' function togglemenu()') |
|
|
|
|
$("#menu").toggle() |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
function checkFeature(id, query) { |
|
|
|
|
log(' function checkFeature(id, query)') |
|
|
|
|
if (query) $('#'+id) |
|
|
|
|
.css('color', 'green') |
|
|
|
|
.prepend('<span>✔</span>') |
|
|
|
@ -338,6 +359,7 @@ function SafeChat() { |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
this.checkFeatures = function() { |
|
|
|
|
log(' this.checkFeatures = function()') |
|
|
|
|
$('ul.features').css('list-style-type', 'none') |
|
|
|
|
checkFeature("localstorage", Storage) |
|
|
|
|
checkFeature("indexeddb", window.indexedDB) |
|
|
|
@ -350,6 +372,7 @@ function SafeChat() { |
|
|
|
|
/// @{
|
|
|
|
|
|
|
|
|
|
this.newuser = function() { |
|
|
|
|
log(' this.newuser = function()') |
|
|
|
|
show('newuser') |
|
|
|
|
} |
|
|
|
|
|
|
|
|
@ -357,12 +380,14 @@ function SafeChat() { |
|
|
|
|
var pwd = false |
|
|
|
|
|
|
|
|
|
function invalid(usr) { |
|
|
|
|
log(' function invalid(usr)') |
|
|
|
|
return !user || !user.exists && user.name.length<3 |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
this.available = function(usr) { |
|
|
|
|
log(' this.available = function(usr)') |
|
|
|
|
user = usr |
|
|
|
|
console.log("props:", invalid(user) || !pwd) |
|
|
|
|
log("props:", invalid(user) || !pwd) |
|
|
|
|
$("#createuser").prop(":disabled", invalid(user) || !pwd) |
|
|
|
|
if (user.length==0) |
|
|
|
|
notice("please chose a user name") |
|
|
|
@ -377,8 +402,10 @@ function SafeChat() { |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
this.passwords = function(pwd1, pwd2) { |
|
|
|
|
log(' this.passwords = function(pwd1, pwd2)') |
|
|
|
|
return |
|
|
|
|
pwd = pwd1==pwd2 && pwd1.length>5 |
|
|
|
|
console.log("props:", invalid(user) || !pwd) |
|
|
|
|
log("props:", invalid(user) || !pwd) |
|
|
|
|
$("#createuser").prop(":disabled", invalid(user) || !pwd) |
|
|
|
|
if (pwd1.length==0) |
|
|
|
|
notice('please chose a password') |
|
|
|
@ -395,6 +422,7 @@ function SafeChat() { |
|
|
|
|
/// @}
|
|
|
|
|
|
|
|
|
|
function DataTransfer() { |
|
|
|
|
log(' function DataTransfer()') |
|
|
|
|
|
|
|
|
|
var reboottimer = null |
|
|
|
|
var data = new DataTransfer() |
|
|
|
@ -419,6 +447,7 @@ function SafeChat() { |
|
|
|
|
|
|
|
|
|
/// Upload Profile Backup
|
|
|
|
|
function restore(evt) { |
|
|
|
|
log(' function restore(evt)') |
|
|
|
|
for (var i=0, f; f=evt.target.files[i]; ++i) { |
|
|
|
|
var file = f |
|
|
|
|
var reader = new FileReader() |
|
|
|
@ -431,7 +460,7 @@ function SafeChat() { |
|
|
|
|
localStorage.pubkey = parsed.pubkey |
|
|
|
|
localStorage.privkey = parsed.privkey |
|
|
|
|
success("backup is restored") |
|
|
|
|
console.log("reboot after restore in 2s") |
|
|
|
|
log("reboot after restore in 2s") |
|
|
|
|
if (!reboottimer && reboot) reboottimer = setTimeout(function() { |
|
|
|
|
reboottimer = null |
|
|
|
|
}, 2000) |
|
|
|
@ -452,6 +481,7 @@ function SafeChat() { |
|
|
|
|
//==============================================================================
|
|
|
|
|
/// @class Controller defines the programm flow
|
|
|
|
|
function Controller(view) { |
|
|
|
|
log(' function Controller(view)') |
|
|
|
|
|
|
|
|
|
var db = new DataBase() |
|
|
|
|
var crypto = new Crypto(this) |
|
|
|
@ -468,35 +498,48 @@ function SafeChat() { |
|
|
|
|
|
|
|
|
|
/// @}
|
|
|
|
|
|
|
|
|
|
/// @name access to view
|
|
|
|
|
/// @{
|
|
|
|
|
|
|
|
|
|
this.togglemenu = view.togglemenu |
|
|
|
|
|
|
|
|
|
/// @}
|
|
|
|
|
|
|
|
|
|
/// @name signals from server
|
|
|
|
|
/// @{
|
|
|
|
|
|
|
|
|
|
function fail(msg) { |
|
|
|
|
console.log('rcv-> fail('+msg+')') |
|
|
|
|
log(' function fail(msg)') |
|
|
|
|
log('rcv-> fail('+msg+')') |
|
|
|
|
error(msg) |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
function loggedin() { |
|
|
|
|
console.log("rcv-> login") |
|
|
|
|
log(' function loggedin()') |
|
|
|
|
log("rcv-> login") |
|
|
|
|
success("login successful") |
|
|
|
|
chat() |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
function user(usr) { |
|
|
|
|
console.log("rcv-> user") |
|
|
|
|
log(' function user(usr)') |
|
|
|
|
log("rcv-> user") |
|
|
|
|
if (usr.exits) users.add(usr) |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
function users() { |
|
|
|
|
console.log("rcv-> users") |
|
|
|
|
log(' function users()') |
|
|
|
|
log("rcv-> users") |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
function message(msg) { |
|
|
|
|
console.log("rcv-> message") |
|
|
|
|
log(' function message(msg)') |
|
|
|
|
log("rcv-> message") |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
function messages(msgs) { |
|
|
|
|
console.log("rcv-> messages") |
|
|
|
|
log(' function messages(msgs)') |
|
|
|
|
log("rcv-> messages") |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
this.connected = view.connected |
|
|
|
@ -513,6 +556,8 @@ function SafeChat() { |
|
|
|
|
/// @{
|
|
|
|
|
|
|
|
|
|
this.lookup = function(usr) { |
|
|
|
|
log(' this.lookup = function(usr)') |
|
|
|
|
return |
|
|
|
|
if (usr.length > 2) communication.lookup(uid(usr), function(res) { |
|
|
|
|
view.available(res) |
|
|
|
|
}) |
|
|
|
@ -521,6 +566,7 @@ function SafeChat() { |
|
|
|
|
this.checkpasswords = view.passwords |
|
|
|
|
|
|
|
|
|
this.createuser = function(name, pwd) { |
|
|
|
|
log(' this.createuser = function(name, pwd)') |
|
|
|
|
crypto.createuser(name, name+'@'+hostname, pwd).then(function() { |
|
|
|
|
if (!crypto.password(pwd)) |
|
|
|
|
fatal("private key decryption failed") |
|
|
|
@ -534,39 +580,53 @@ function SafeChat() { |
|
|
|
|
/// @}
|
|
|
|
|
|
|
|
|
|
function initBrowser() { |
|
|
|
|
window.indexedDB = window.indexedDB || window.mozIndexedDB || window.webkitIndexedDB || window.msIndexedDB |
|
|
|
|
log(' function initBrowser()') |
|
|
|
|
log('A') |
|
|
|
|
//window.indexedDB = window.indexedDB || window.mozIndexedDB || window.webkitIndexedDB || window.msIndexedDB
|
|
|
|
|
log('B') |
|
|
|
|
window.IDBTransaction = window.IDBTransaction || window.webkitIDBTransaction || window.msIDBTransaction |
|
|
|
|
log('C') |
|
|
|
|
window.IDBKeyRange = window.IDBKeyRange || window.webkitIDBKeyRange || window.msIDBKeyRange |
|
|
|
|
log('D') |
|
|
|
|
navigator.vibrate = navigator.vibrate || navigator.webkitVibrate || navigator.mozVibrate || navigator.msVibrate |
|
|
|
|
log('E') |
|
|
|
|
log(' end of function initBrowser()') |
|
|
|
|
return window.indexedDB && window.crypto.getRandomValues && Storage |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
var newuser = view.newuser |
|
|
|
|
|
|
|
|
|
function chat() { |
|
|
|
|
log(' function chat()') |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
function password() { |
|
|
|
|
|
|
|
|
|
log(' function password()') |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
function login() { |
|
|
|
|
log(' function login()') |
|
|
|
|
if (!crypto.key()) newuser(); else password(); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
this.run = function() { |
|
|
|
|
log(' this.run = function()') |
|
|
|
|
login() |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
this.start = function() { |
|
|
|
|
log(' this.start = function()') |
|
|
|
|
view.reboot = this.run |
|
|
|
|
var compatible = initBrowser() |
|
|
|
|
view.checkFeatures() |
|
|
|
|
if (!compatible) |
|
|
|
|
if (!compatible) { |
|
|
|
|
log('incompatible') |
|
|
|
|
view.fatal("your browser is not supported") |
|
|
|
|
else |
|
|
|
|
} else { |
|
|
|
|
log('incompatible') |
|
|
|
|
this.run() |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
@ -582,12 +642,14 @@ var filecontent = new Array() ///< temporary storage for attachments |
|
|
|
|
var reboottimer = null |
|
|
|
|
|
|
|
|
|
function connectionstatus() { |
|
|
|
|
log('function connectionstatus()') |
|
|
|
|
if (socket.connected) connected(); else disconnected(); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/// Configure local groups
|
|
|
|
|
/** … */ |
|
|
|
|
function groups() { |
|
|
|
|
log('function groups()') |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/// Check if password is set and matches the repeated password
|
|
|
|
@ -602,6 +664,7 @@ function groups() { |
|
|
|
|
@param pwd The password. |
|
|
|
|
@param pwd2 The repeated password. */ |
|
|
|
|
function checkpwd(pwd, pwd2) { |
|
|
|
|
log('function checkpwd(pwd, pwd2)') |
|
|
|
|
$("#register").submit(function(event) { |
|
|
|
|
return false |
|
|
|
|
}) |
|
|
|
@ -624,6 +687,7 @@ function checkpwd(pwd, pwd2) { |
|
|
|
|
/** Calls checknewuser.php on server and enables the message submit |
|
|
|
|
button if the receiver of the message exists on the server. */ |
|
|
|
|
function checkpartner(user) { |
|
|
|
|
log('function checkpartner(user)') |
|
|
|
|
$("#chat").submit(function(event) { |
|
|
|
|
return false |
|
|
|
|
}) |
|
|
|
@ -633,6 +697,7 @@ function checkpartner(user) { |
|
|
|
|
/// Create Local Public-/Private-Key Pair
|
|
|
|
|
/** Called if user has not yet his keys, just generates a new key pair. */ |
|
|
|
|
function createkeypair(user, pwd) { |
|
|
|
|
log('function createkeypair(user, pwd)') |
|
|
|
|
notice("generating keys") |
|
|
|
|
openpgp.generateKey({ |
|
|
|
|
numBits: 4096, |
|
|
|
@ -644,7 +709,7 @@ function createkeypair(user, pwd) { |
|
|
|
|
localStorage.privkey = keyPair.privateKeyArmored |
|
|
|
|
login() |
|
|
|
|
}).catch(function(e) { |
|
|
|
|
console.log(e) |
|
|
|
|
log(e) |
|
|
|
|
error("generating key pairs failed") |
|
|
|
|
}) |
|
|
|
|
} |
|
|
|
@ -652,6 +717,7 @@ function createkeypair(user, pwd) { |
|
|
|
|
/// Get Own Public Key
|
|
|
|
|
/** @return public key object */ |
|
|
|
|
function publicKey() { |
|
|
|
|
log('function publicKey()') |
|
|
|
|
if (typeof localStorage.pubkey == 'undefined') { |
|
|
|
|
if (typeof localStorage.pubKey == 'undefined') { |
|
|
|
|
return null |
|
|
|
@ -666,6 +732,7 @@ function publicKey() { |
|
|
|
|
/// Get Own Private Key
|
|
|
|
|
/** @return private key object */ |
|
|
|
|
function privateKey() { |
|
|
|
|
log('function privateKey()') |
|
|
|
|
if (typeof localStorage.privkey == 'undefined') { |
|
|
|
|
if (typeof localStorage.privKey == 'undefined') { |
|
|
|
|
return null |
|
|
|
@ -680,6 +747,7 @@ function privateKey() { |
|
|
|
|
/// Get Own User Name
|
|
|
|
|
/** Get user name as user id of first public key */ |
|
|
|
|
function userid() { |
|
|
|
|
log('function userid()') |
|
|
|
|
if (!publicKey() || |
|
|
|
|
publicKey().keys.length < 1 || |
|
|
|
|
publicKey().keys[0].getUserIds().length < 1) return null |
|
|
|
@ -689,6 +757,7 @@ function userid() { |
|
|
|
|
/// Clear Message Text And Attachments
|
|
|
|
|
/** Does not remove the receiver's name */ |
|
|
|
|
function clearmessage() { |
|
|
|
|
log('function clearmessage()') |
|
|
|
|
$("#message").prop(":disabled", true) |
|
|
|
|
filecontent = new Array() |
|
|
|
|
$('#preview').empty() |
|
|
|
@ -697,6 +766,7 @@ function clearmessage() { |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
function guessfilename(mimetype, user, date) { |
|
|
|
|
log('function guessfilename(mimetype, user, date)') |
|
|
|
|
if (!user) user = userid() |
|
|
|
|
if (!date) date = new Date() |
|
|
|
|
var ext = mimetype.replace(/.*\/(x-)?/i, "") |
|
|
|
@ -706,8 +776,9 @@ function guessfilename(mimetype, user, date) { |
|
|
|
|
|
|
|
|
|
/// Display Image Attachments
|
|
|
|
|
function attachments(files, id, from, date) { |
|
|
|
|
log('function attachments(files, id, from, date)') |
|
|
|
|
if (files) files.forEach(function(file) { |
|
|
|
|
console.log(file) |
|
|
|
|
log(file) |
|
|
|
|
if (!file.name) file.name = guessfilename(file.type, from, date) |
|
|
|
|
var a = document.createElement('a') |
|
|
|
|
a.href = file.content |
|
|
|
@ -737,6 +808,7 @@ function attachments(files, id, from, date) { |
|
|
|
|
var recorder |
|
|
|
|
|
|
|
|
|
function done() { |
|
|
|
|
log('function done()') |
|
|
|
|
if (recorder) { |
|
|
|
|
recorder.stop() |
|
|
|
|
recorder.recording(function(data) { |
|
|
|
@ -747,6 +819,7 @@ function done() { |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
function abort() { |
|
|
|
|
log('function abort()') |
|
|
|
|
if (recorder) { |
|
|
|
|
$("#videorecorder").hide() |
|
|
|
|
recorder.release() |
|
|
|
@ -757,6 +830,7 @@ function abort() { |
|
|
|
|
|
|
|
|
|
/// Record Video from builtin camera
|
|
|
|
|
function recordvideo() { |
|
|
|
|
log('function recordvideo()') |
|
|
|
|
try { |
|
|
|
|
abort() |
|
|
|
|
$("#videorecorder").show() |
|
|
|
@ -776,12 +850,13 @@ function recordvideo() { |
|
|
|
|
recorder.start() |
|
|
|
|
}) |
|
|
|
|
} catch (e) { |
|
|
|
|
console.log(e) |
|
|
|
|
log(e) |
|
|
|
|
error("cannot access camera", true) |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
function previewfile(content, type, name) { |
|
|
|
|
log('function previewfile(content, type, name)') |
|
|
|
|
if (!name) name = guessfilename(type) |
|
|
|
|
if (type.match('^image/')) { |
|
|
|
|
var img = document.createElement("img") |
|
|
|
@ -836,6 +911,7 @@ function previewfile(content, type, name) { |
|
|
|
|
|
|
|
|
|
Stores data in global variable @ref filecontent. */ |
|
|
|
|
function fileupload(evt) { |
|
|
|
|
log('function fileupload(evt)') |
|
|
|
|
if (!window.FileReader) |
|
|
|
|
return error("your browser does not support file upload", true) |
|
|
|
|
for (var i=0, f; f=evt.target.files[i]; ++i) { |
|
|
|
@ -857,6 +933,7 @@ function fileupload(evt) { |
|
|
|
|
|
|
|
|
|
@param name The receiver's name. */ |
|
|
|
|
function setreceiver(name) { |
|
|
|
|
log('function setreceiver(name)') |
|
|
|
|
$("#recv").val(name) |
|
|
|
|
checkpartner(name) |
|
|
|
|
$("#msg").focus() |
|
|
|
@ -864,21 +941,23 @@ function setreceiver(name) { |
|
|
|
|
|
|
|
|
|
var userMap = null |
|
|
|
|
function users(userlist) { |
|
|
|
|
console.log("rcv-> users") |
|
|
|
|
log('function users(userlist)') |
|
|
|
|
log("rcv-> users") |
|
|
|
|
userMap = new Array() |
|
|
|
|
$("#allusers").empty() |
|
|
|
|
userlist.forEach(function(usr) { |
|
|
|
|
userMap[usr.name] = usr.pubkey |
|
|
|
|
$("#allusers").append('<option value="'+htmlenc(usr.name)+'">') |
|
|
|
|
$("#allusers").hide() |
|
|
|
|
console.log(" user: "+usr.name) |
|
|
|
|
log(" user: "+usr.name) |
|
|
|
|
}) |
|
|
|
|
localStorage.userMap = JSON.stringify(userMap) |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
function user(usr) { |
|
|
|
|
if (usr.exists) console.log("rcv-> user("+usr.name+")") |
|
|
|
|
else console.log("rcv-> user("+usr.name+"): name is available") |
|
|
|
|
log('function user(usr)') |
|
|
|
|
if (usr.exists) log("rcv-> user("+usr.name+")") |
|
|
|
|
else log("rcv-> user("+usr.name+"): name is available") |
|
|
|
|
if ($("#newuser").is(":visible") && usr.name==uid($('#user').val())) { |
|
|
|
|
// same username as in the create user form
|
|
|
|
|
$("#createuser").prop("disabled", usr.exists) // todo: check password
|
|
|
|
@ -912,13 +991,15 @@ function user(usr) { |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
function queryuser(usr) { |
|
|
|
|
console.log("query user: "+uid(usr)) |
|
|
|
|
log('function queryuser(usr)') |
|
|
|
|
log("query user: "+uid(usr)) |
|
|
|
|
socket.emit("user", uid(usr)) |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/// Get a user's public key.
|
|
|
|
|
/** The first time, gets it from the server, later from the cache. */ |
|
|
|
|
function getPublicKey(user) { |
|
|
|
|
log('function getPublicKey(user)') |
|
|
|
|
var deferredObject = $.Deferred() |
|
|
|
|
if (userMap && userMap[user]) deferredObject.resolve(userMap[user]) |
|
|
|
|
else deferredObject.reject("unknown user") |
|
|
|
@ -927,7 +1008,8 @@ function getPublicKey(user) { |
|
|
|
|
|
|
|
|
|
/// Received a list of messages from server
|
|
|
|
|
function messages(msgs) { |
|
|
|
|
console.log("rcv-> messages("+msgs.length+")") |
|
|
|
|
log('function messages(msgs)') |
|
|
|
|
log("rcv-> messages("+msgs.length+")") |
|
|
|
|
if (!password || !privateKey()) |
|
|
|
|
return setTimeout(function() {emit("messages")}, 1000) // try again later
|
|
|
|
|
show("allmessages") |
|
|
|
@ -938,7 +1020,8 @@ function messages(msgs) { |
|
|
|
|
|
|
|
|
|
/// Received a message from server
|
|
|
|
|
function message(m, internal) { |
|
|
|
|
if (!internal) console.log("rcv-> message("+m.user+")") |
|
|
|
|
log('function message(m, internal)') |
|
|
|
|
if (!internal) log("rcv-> message("+m.user+")") |
|
|
|
|
if (!password || !privateKey()) return |
|
|
|
|
var key=openpgp.key.readArmored(m.pubkey) |
|
|
|
|
if (key.err) return error("key of sender unreadable", true) |
|
|
|
@ -990,6 +1073,7 @@ function message(m, internal) { |
|
|
|
|
/** User wants to send a message. Encrypt message with own private and |
|
|
|
|
the receiver's public key, then send it to the server. */ |
|
|
|
|
function sendmessage(recv, txt) { |
|
|
|
|
log('function sendmessage(recv, txt)') |
|
|
|
|
notice("1/3 preparing message …") |
|
|
|
|
$("#message").prop(":disabled", true) |
|
|
|
|
getPublicKey(recv) // get receiver's public key
|
|
|
|
@ -1031,6 +1115,8 @@ function sendmessage(recv, txt) { |
|
|
|
|
|
|
|
|
|
@param pwd The password to check. */ |
|
|
|
|
function setpw(pwd) { |
|
|
|
|
log('function setpw(pwd)') |
|
|
|
|
return |
|
|
|
|
if (privateKey().keys[0].decrypt(pwd)) { |
|
|
|
|
success("password matches") |
|
|
|
|
$("#removeKey").hide() |
|
|
|
@ -1047,12 +1133,14 @@ function setpw(pwd) { |
|
|
|
|
setpw() continues automatically. No submit is required by the |
|
|
|
|
user. */ |
|
|
|
|
function getpwd() { |
|
|
|
|
log('function getpwd()') |
|
|
|
|
if (password) return |
|
|
|
|
$("#removeKey").show() |
|
|
|
|
show("getpwd") |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
function deleteUser() { |
|
|
|
|
log('function deleteUser()') |
|
|
|
|
var uid = userid() |
|
|
|
|
localStorage.removeItem(pubkey) |
|
|
|
|
localStorage.removeItem(privkey) |
|
|
|
@ -1060,6 +1148,7 @@ function deleteUser() { |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
function removeKey() { |
|
|
|
|
log('function removeKey()') |
|
|
|
|
togglemenu() |
|
|
|
|
$("#removeKey").hide() |
|
|
|
|
show('forgotpassword') |
|
|
|
@ -1070,6 +1159,7 @@ function removeKey() { |
|
|
|
|
get() which polls for new messages. */ |
|
|
|
|
var firsttime = true |
|
|
|
|
function chat() { |
|
|
|
|
log('function chat()') |
|
|
|
|
if (!password) return getpwd() |
|
|
|
|
show("chat") |
|
|
|
|
if (firsttime && $('#msgs').is(':empty')) { |
|
|
|
@ -1091,6 +1181,7 @@ function chat() { |
|
|
|
|
different, then this is a complete failure, something went |
|
|
|
|
terribly wrong. */ |
|
|
|
|
function login() { |
|
|
|
|
log('function login()') |
|
|
|
|
$("#username").html(userid()+"@"+hostname) |
|
|
|
|
emit("login", {name: userid(), |
|
|
|
|
pubkey: localStorage.pubkey}) |
|
|
|
@ -1101,11 +1192,13 @@ function login() { |
|
|
|
|
/** Shows user creation form. On submit, a private key is generated in |
|
|
|
|
createkeypair(), then login() creates the user. */ |
|
|
|
|
function newuser() { |
|
|
|
|
log('function newuser()') |
|
|
|
|
show("newuser") |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/// Check if local storage is available
|
|
|
|
|
function checkLocalStorage() { |
|
|
|
|
log('function checkLocalStorage()') |
|
|
|
|
var test = 'test' |
|
|
|
|
try { |
|
|
|
|
localStorage.setItem(test, test) |
|
|
|
@ -1121,6 +1214,7 @@ function checkLocalStorage() { |
|
|
|
|
/// Initial Function: Startup
|
|
|
|
|
/** Decide whether to login or to create a new user */ |
|
|
|
|
function start() { |
|
|
|
|
log('function start()') |
|
|
|
|
$("#menu").hide() |
|
|
|
|
//show("startup")
|
|
|
|
|
if (checkLocalStorage()) |
|
|
|
@ -1131,7 +1225,7 @@ function start() { |
|
|
|
|
login() |
|
|
|
|
} |
|
|
|
|
} catch (m) { |
|
|
|
|
console.log(m.stack) |
|
|
|
|
log(m.stack) |
|
|
|
|
error(m) |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
@ -1139,10 +1233,12 @@ function start() { |
|
|
|
|
var safechat = new SafeChat() |
|
|
|
|
|
|
|
|
|
function init() { |
|
|
|
|
log('function init()') |
|
|
|
|
safechat.start() |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
function old() { |
|
|
|
|
log('function old()') |
|
|
|
|
/// On Load, Call @ref start
|
|
|
|
|
$(window.onbeforeunload = function() { |
|
|
|
|
return "Are you sure you want to navigate away?" |
|
|
|
@ -1155,9 +1251,9 @@ function old() { |
|
|
|
|
}, false) |
|
|
|
|
connectionstatus() |
|
|
|
|
if (openpgp.initWorker("openpgp.worker.min.js")) |
|
|
|
|
console.log("asynchronous openpgp enabled") |
|
|
|
|
log("asynchronous openpgp enabled") |
|
|
|
|
else |
|
|
|
|
console.log("asynchronous openpgp failed") |
|
|
|
|
log("asynchronous openpgp failed") |
|
|
|
|
emit('users') |
|
|
|
|
start() |
|
|
|
|
} |
|
|
|
|