about to be able to create user
This commit is contained in:
@@ -41,9 +41,15 @@ function SafeChat() {
|
|||||||
|
|
||||||
/// Create UID from a name by appending an E-Mail
|
/// Create UID from a name by appending an E-Mail
|
||||||
function uid(name) {
|
function uid(name) {
|
||||||
return name+' <'+name+'@'+hostname+'>'
|
return name+' <'+mail(name)+'>'
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function mail(name) {
|
||||||
|
var hostname = window.location.hostname!='localhost'?window.location.hostname:'safechat.ch'
|
||||||
|
return name+'@'+hostname
|
||||||
|
}
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
/// @class Crypto cryptographic functions
|
/// @class Crypto cryptographic functions
|
||||||
/** @param view is of class SafeChat.View */
|
/** @param view is of class SafeChat.View */
|
||||||
function Crypto(controller) {
|
function Crypto(controller) {
|
||||||
@@ -51,42 +57,23 @@ function SafeChat() {
|
|||||||
/// cache client's key from local strorage
|
/// cache client's key from local strorage
|
||||||
var k = null
|
var k = null
|
||||||
|
|
||||||
/// detect hosstname, default to safechat.ch
|
/// detect hostname, default to safechat.ch
|
||||||
var hostname = window.location.hostname!='localhost'?window.location.hostname:'safechat.ch'
|
|
||||||
|
|
||||||
/// get user key
|
/// get user key
|
||||||
/** @internal key ist cached in k
|
/** @internal key ist cached in k
|
||||||
@return key */
|
@return key */
|
||||||
function key() {
|
this.key = function() {
|
||||||
if (k) return k
|
if (k) return k // cached key
|
||||||
if (typeof localStorage.key == 'undefined') return null
|
if (typeof localStorage.privkey === 'undefined') return null
|
||||||
return k = openpgp.key.readArmored(localStorage.key)
|
return k = openpgp.key.readArmored(localStorage.privkey)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// get own user name
|
/// get own user name
|
||||||
/** get user name as user id of first public key */
|
/** get user name as user id of first public key */
|
||||||
function user() {
|
this.user = function() {
|
||||||
if (k || key()) return k.pub.keys[0].getUserIds()[0]
|
if (k || key()) return k.pub.keys[0].getUserIds()[0]
|
||||||
return null
|
return null
|
||||||
}
|
}
|
||||||
|
|
||||||
/// create New User
|
|
||||||
function createuser(user, email, pwd) {
|
|
||||||
controller.notice("generating keys")
|
|
||||||
openpgp.generateKey({
|
|
||||||
numBits: 4096,
|
|
||||||
userIds: [{name: user, email: email}],
|
|
||||||
passphrase: pwd
|
|
||||||
}).then(function(keyPair) {
|
|
||||||
controller.success("keys generated")
|
|
||||||
localStorage.key = keyPair.privateKeyArmored
|
|
||||||
k = keyPair.key
|
|
||||||
}).catch(function(e) {
|
|
||||||
console.log(e)
|
|
||||||
controller.fatal("generating key pairs failed")
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
/// open private key with password
|
/// open private key with password
|
||||||
/** @return @c true if password matches */
|
/** @return @c true if password matches */
|
||||||
function password(pwd) {
|
function password(pwd) {
|
||||||
@@ -116,8 +103,15 @@ function SafeChat() {
|
|||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
if (openpgp.initWorker("openpgp.worker.min.js"))
|
||||||
|
console.log("asynchronous openpgp enabled")
|
||||||
|
else
|
||||||
|
console.log("asynchronous openpgp failed")
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
/// database that stores in indexed db
|
/// database that stores in indexed db
|
||||||
function DataBase() {
|
function DataBase() {
|
||||||
|
|
||||||
@@ -126,6 +120,7 @@ function SafeChat() {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
/// manage local copy of users
|
/// manage local copy of users
|
||||||
function Users() {
|
function Users() {
|
||||||
|
|
||||||
@@ -142,6 +137,7 @@ function SafeChat() {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
/// manage local copy of messages
|
/// manage local copy of messages
|
||||||
function Messages() {
|
function Messages() {
|
||||||
|
|
||||||
@@ -152,6 +148,7 @@ function SafeChat() {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
/// @class Communication client socket communication
|
/// @class Communication client socket communication
|
||||||
/** @param view is of class SafeChat.View */
|
/** @param view is of class SafeChat.View */
|
||||||
function Communication(controller) {
|
function Communication(controller) {
|
||||||
@@ -163,9 +160,13 @@ function SafeChat() {
|
|||||||
socket.broadcast.emit(signal, data)
|
socket.broadcast.emit(signal, data)
|
||||||
}
|
}
|
||||||
|
|
||||||
function emit(signal, data) {
|
function emit(signal, data, next) {
|
||||||
console.log("<-snd "+signal)
|
console.log("<-snd "+signal)
|
||||||
socket.emit(signal, data)
|
socket.emit(signal, data, next)
|
||||||
|
}
|
||||||
|
|
||||||
|
this.lookup = function(usr, next) {
|
||||||
|
emit('user', usr, next)
|
||||||
}
|
}
|
||||||
|
|
||||||
socket
|
socket
|
||||||
@@ -183,6 +184,7 @@ function SafeChat() {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
/// @class View provides the glue to the GUI in the index.ejs file
|
/// @class View provides the glue to the GUI in the index.ejs file
|
||||||
/** View provides the following callbacks:
|
/** View provides the following callbacks:
|
||||||
- status updates:
|
- status updates:
|
||||||
@@ -299,7 +301,7 @@ function SafeChat() {
|
|||||||
@param msg (optional) the success message text */
|
@param msg (optional) the success message text */
|
||||||
function show(id, msg) {
|
function show(id, msg) {
|
||||||
console.log("state: "+id)
|
console.log("state: "+id)
|
||||||
if (msg) success(msg) else $("#status").hide()
|
if (msg) success(msg); else $("#status").hide();
|
||||||
$("#main").children(":not(#"+id+")").hide()
|
$("#main").children(":not(#"+id+")").hide()
|
||||||
$("#main #"+id).show()
|
$("#main #"+id).show()
|
||||||
$("#main #"+id+" form input:first-child").focus()
|
$("#main #"+id+" form input:first-child").focus()
|
||||||
@@ -327,21 +329,15 @@ function SafeChat() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function checkFeature(id, query) {
|
function checkFeature(id, query) {
|
||||||
if (query) $('#'+id+':before')
|
|
||||||
.css('color', 'green')
|
|
||||||
.css('content', '✔')
|
|
||||||
else $('#'+id+':before')
|
|
||||||
.css('color', 'red')
|
|
||||||
.css('content', '✘')
|
|
||||||
if (query) $('#'+id)
|
if (query) $('#'+id)
|
||||||
.css('color', 'green')
|
.css('color', 'green')
|
||||||
.css('text-decoration', 'line-through')
|
.prepend('<span>✔</span>')
|
||||||
else $('#'+id)
|
else $('#'+id)
|
||||||
.css('color', 'red')
|
.css('color', 'red')
|
||||||
.css('text-decoration', 'none')
|
.prepend('<span>✘</span>')
|
||||||
}
|
}
|
||||||
|
|
||||||
function checkFeatures() {
|
this.checkFeatures = function() {
|
||||||
$('ul.features').css('list-style-type', 'none')
|
$('ul.features').css('list-style-type', 'none')
|
||||||
checkFeature("localstorage", Storage)
|
checkFeature("localstorage", Storage)
|
||||||
checkFeature("indexeddb", window.indexedDB)
|
checkFeature("indexeddb", window.indexedDB)
|
||||||
@@ -350,6 +346,54 @@ function SafeChat() {
|
|||||||
checkFeature("filereader", window.FileReader)
|
checkFeature("filereader", window.FileReader)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// @name create new user
|
||||||
|
/// @{
|
||||||
|
|
||||||
|
this.newuser = function() {
|
||||||
|
show('newuser')
|
||||||
|
}
|
||||||
|
|
||||||
|
var user = null
|
||||||
|
var pwd = false
|
||||||
|
|
||||||
|
function invalid(usr) {
|
||||||
|
return !user || !user.exists && user.name.length<3
|
||||||
|
}
|
||||||
|
|
||||||
|
this.available = function(usr) {
|
||||||
|
user = usr
|
||||||
|
console.log("props:", invalid(user) || !pwd)
|
||||||
|
$("#createuser").prop(":disabled", invalid(user) || !pwd)
|
||||||
|
if (user.length==0)
|
||||||
|
notice("please chose a user name")
|
||||||
|
else if (user.length<3)
|
||||||
|
notice("please chose a longer user name")
|
||||||
|
else if (user.exists)
|
||||||
|
notice("user name is already in use")
|
||||||
|
else if (!pwd)
|
||||||
|
notice("please chose a password")
|
||||||
|
else
|
||||||
|
success("user is ready to be created")
|
||||||
|
}
|
||||||
|
|
||||||
|
this.passwords = function(pwd1, pwd2) {
|
||||||
|
pwd = pwd1==pwd2 && pwd1.length>5
|
||||||
|
console.log("props:", invalid(user) || !pwd)
|
||||||
|
$("#createuser").prop(":disabled", invalid(user) || !pwd)
|
||||||
|
if (pwd1.length==0)
|
||||||
|
notice('please chose a password')
|
||||||
|
else if (pwd1.length<6)
|
||||||
|
notice('please chose a longer password')
|
||||||
|
else if (pwd1 != pwd2)
|
||||||
|
notice("passwords don't match")
|
||||||
|
else if (invalid(user))
|
||||||
|
notice("please chose a user name")
|
||||||
|
else
|
||||||
|
success("user is ready to be created")
|
||||||
|
}
|
||||||
|
|
||||||
|
/// @}
|
||||||
|
|
||||||
function DataTransfer() {
|
function DataTransfer() {
|
||||||
|
|
||||||
var reboottimer = null
|
var reboottimer = null
|
||||||
@@ -405,10 +449,11 @@ function SafeChat() {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
/// @class Controller defines the programm flow
|
/// @class Controller defines the programm flow
|
||||||
function Controller(view) {
|
function Controller(view) {
|
||||||
|
|
||||||
var db = new Database()
|
var db = new DataBase()
|
||||||
var crypto = new Crypto(this)
|
var crypto = new Crypto(this)
|
||||||
var communication = new Communication(this)
|
var communication = new Communication(this)
|
||||||
var users = new Users()
|
var users = new Users()
|
||||||
@@ -461,6 +506,33 @@ function SafeChat() {
|
|||||||
|
|
||||||
// @}
|
// @}
|
||||||
|
|
||||||
|
/// @name signals from view
|
||||||
|
/// @{
|
||||||
|
|
||||||
|
/// @name new user registration
|
||||||
|
/// @{
|
||||||
|
|
||||||
|
this.lookup = function(usr) {
|
||||||
|
if (usr.length > 2) communication.lookup(uid(usr), function(res) {
|
||||||
|
view.available(res)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
this.checkpasswords = view.passwords
|
||||||
|
|
||||||
|
this.createuser = function(name, pwd) {
|
||||||
|
crypto.createuser(name, name+'@'+hostname, pwd).then(function() {
|
||||||
|
if (!crypto.password(pwd))
|
||||||
|
fatal("private key decryption failed")
|
||||||
|
else
|
||||||
|
chat()
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
/// @}
|
||||||
|
|
||||||
|
/// @}
|
||||||
|
|
||||||
function initBrowser() {
|
function initBrowser() {
|
||||||
window.indexedDB = window.indexedDB || window.mozIndexedDB || window.webkitIndexedDB || window.msIndexedDB
|
window.indexedDB = window.indexedDB || window.mozIndexedDB || window.webkitIndexedDB || window.msIndexedDB
|
||||||
window.IDBTransaction = window.IDBTransaction || window.webkitIDBTransaction || window.msIDBTransaction
|
window.IDBTransaction = window.IDBTransaction || window.webkitIDBTransaction || window.msIDBTransaction
|
||||||
@@ -469,52 +541,57 @@ function SafeChat() {
|
|||||||
return window.indexedDB && window.crypto.getRandomValues && Storage
|
return window.indexedDB && window.crypto.getRandomValues && Storage
|
||||||
}
|
}
|
||||||
|
|
||||||
function register() {
|
var newuser = view.newuser
|
||||||
|
|
||||||
|
function chat() {
|
||||||
|
}
|
||||||
|
|
||||||
|
function password() {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function login() {
|
function login() {
|
||||||
if (!crypto.key()) register()
|
if (!crypto.key()) newuser(); else password();
|
||||||
else password()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function run() {
|
this.run = function() {
|
||||||
login()
|
login()
|
||||||
}
|
}
|
||||||
|
|
||||||
function start() {
|
this.start = function() {
|
||||||
view.reboot = run
|
view.reboot = this.run
|
||||||
var compatible = initBrowser()
|
var compatible = initBrowser()
|
||||||
view.checkFeatures()
|
view.checkFeatures()
|
||||||
if (!compatible)
|
if (!compatible)
|
||||||
view.fatal("your browser is not supported")
|
view.fatal("your browser is not supported")
|
||||||
else
|
else
|
||||||
run()
|
this.run()
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//==============================================================================
|
//==============================================================================
|
||||||
|
|
||||||
//------------------------------------------------------------------------------
|
|
||||||
return new Controller(new View())
|
return new Controller(new View())
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
var filecontent = new Array() ///< temporary storage for attachments
|
//==============================================================================
|
||||||
var reboottimer = null
|
//------------------------------------------------------------------------------
|
||||||
|
|
||||||
function connectionstatus() {
|
var filecontent = new Array() ///< temporary storage for attachments
|
||||||
if (socket.connected) connected() else disconnected()
|
var reboottimer = null
|
||||||
}
|
|
||||||
|
|
||||||
/// Configure local groups
|
function connectionstatus() {
|
||||||
/** … */
|
if (socket.connected) connected(); else disconnected();
|
||||||
function groups() {
|
}
|
||||||
}
|
|
||||||
|
|
||||||
/// Check if password is set and matches the repeated password
|
/// Configure local groups
|
||||||
/** Checks if both passwords are identical and valid and gives
|
/** … */
|
||||||
|
function groups() {
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Check if password is set and matches the repeated password
|
||||||
|
/** Checks if both passwords are identical and valid and gives
|
||||||
feedback to the user.
|
feedback to the user.
|
||||||
|
|
||||||
Called when user edits the password fields.
|
Called when user edits the password fields.
|
||||||
@@ -524,7 +601,7 @@ function SafeChat() {
|
|||||||
|
|
||||||
@param pwd The password.
|
@param pwd The password.
|
||||||
@param pwd2 The repeated password. */
|
@param pwd2 The repeated password. */
|
||||||
function checkpwd(pwd, pwd2) {
|
function checkpwd(pwd, pwd2) {
|
||||||
$("#register").submit(function(event) {
|
$("#register").submit(function(event) {
|
||||||
return false
|
return false
|
||||||
})
|
})
|
||||||
@@ -541,21 +618,21 @@ function SafeChat() {
|
|||||||
else notice("please chose a user name")
|
else notice("please chose a user name")
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Checks if the receiver of a message exists on server.
|
/// Checks if the receiver of a message exists on server.
|
||||||
/** Calls checknewuser.php on server and enables the message submit
|
/** Calls checknewuser.php on server and enables the message submit
|
||||||
button if the receiver of the message exists on the server. */
|
button if the receiver of the message exists on the server. */
|
||||||
function checkpartner(user) {
|
function checkpartner(user) {
|
||||||
$("#chat").submit(function(event) {
|
$("#chat").submit(function(event) {
|
||||||
return false
|
return false
|
||||||
})
|
})
|
||||||
emit("user", uid(user))
|
emit("user", uid(user))
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Create Local Public-/Private-Key Pair
|
/// Create Local Public-/Private-Key Pair
|
||||||
/** Called if user has not yet his keys, just generates a new key pair. */
|
/** Called if user has not yet his keys, just generates a new key pair. */
|
||||||
function createkeypair(user, pwd) {
|
function createkeypair(user, pwd) {
|
||||||
notice("generating keys")
|
notice("generating keys")
|
||||||
openpgp.generateKey({
|
openpgp.generateKey({
|
||||||
numBits: 4096,
|
numBits: 4096,
|
||||||
@@ -570,11 +647,11 @@ function SafeChat() {
|
|||||||
console.log(e)
|
console.log(e)
|
||||||
error("generating key pairs failed")
|
error("generating key pairs failed")
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Get Own Public Key
|
/// Get Own Public Key
|
||||||
/** @return public key object */
|
/** @return public key object */
|
||||||
function publicKey() {
|
function publicKey() {
|
||||||
if (typeof localStorage.pubkey == 'undefined') {
|
if (typeof localStorage.pubkey == 'undefined') {
|
||||||
if (typeof localStorage.pubKey == 'undefined') {
|
if (typeof localStorage.pubKey == 'undefined') {
|
||||||
return null
|
return null
|
||||||
@@ -584,11 +661,11 @@ function SafeChat() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
return openpgp.key.readArmored(localStorage.pubkey)
|
return openpgp.key.readArmored(localStorage.pubkey)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Get Own Private Key
|
/// Get Own Private Key
|
||||||
/** @return private key object */
|
/** @return private key object */
|
||||||
function privateKey() {
|
function privateKey() {
|
||||||
if (typeof localStorage.privkey == 'undefined') {
|
if (typeof localStorage.privkey == 'undefined') {
|
||||||
if (typeof localStorage.privKey == 'undefined') {
|
if (typeof localStorage.privKey == 'undefined') {
|
||||||
return null
|
return null
|
||||||
@@ -598,37 +675,37 @@ function SafeChat() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
return openpgp.key.readArmored(localStorage.privkey)
|
return openpgp.key.readArmored(localStorage.privkey)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Get Own User Name
|
/// Get Own User Name
|
||||||
/** Get user name as user id of first public key */
|
/** Get user name as user id of first public key */
|
||||||
function userid() {
|
function userid() {
|
||||||
if (!publicKey() ||
|
if (!publicKey() ||
|
||||||
publicKey().keys.length < 1 ||
|
publicKey().keys.length < 1 ||
|
||||||
publicKey().keys[0].getUserIds().length < 1) return null
|
publicKey().keys[0].getUserIds().length < 1) return null
|
||||||
return publicKey().keys[0].getUserIds()[0]
|
return publicKey().keys[0].getUserIds()[0]
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Clear Message Text And Attachments
|
/// Clear Message Text And Attachments
|
||||||
/** Does not remove the receiver's name */
|
/** Does not remove the receiver's name */
|
||||||
function clearmessage() {
|
function clearmessage() {
|
||||||
$("#message").prop(":disabled", true)
|
$("#message").prop(":disabled", true)
|
||||||
filecontent = new Array()
|
filecontent = new Array()
|
||||||
$('#preview').empty()
|
$('#preview').empty()
|
||||||
$("#msg").val("")
|
$("#msg").val("")
|
||||||
$("#message").prop(":disabled", false)
|
$("#message").prop(":disabled", false)
|
||||||
}
|
}
|
||||||
|
|
||||||
function guessfilename(mimetype, user, date) {
|
function guessfilename(mimetype, user, date) {
|
||||||
if (!user) user = userid()
|
if (!user) user = userid()
|
||||||
if (!date) date = new Date()
|
if (!date) date = new Date()
|
||||||
var ext = mimetype.replace(/.*\/(x-)?/i, "")
|
var ext = mimetype.replace(/.*\/(x-)?/i, "")
|
||||||
return pad(date.getFullYear())+pad(date.getMonth()+1)+pad(date.getDate())
|
return pad(date.getFullYear())+pad(date.getMonth()+1)+pad(date.getDate())
|
||||||
+"-"+ext+"-"+user+"@"+hostname+'.'+ext
|
+"-"+ext+"-"+user+"@"+hostname+'.'+ext
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Display Image Attachments
|
/// Display Image Attachments
|
||||||
function attachments(files, id, from, date) {
|
function attachments(files, id, from, date) {
|
||||||
if (files) files.forEach(function(file) {
|
if (files) files.forEach(function(file) {
|
||||||
console.log(file)
|
console.log(file)
|
||||||
if (!file.name) file.name = guessfilename(file.type, from, date)
|
if (!file.name) file.name = guessfilename(file.type, from, date)
|
||||||
@@ -655,11 +732,11 @@ function SafeChat() {
|
|||||||
}
|
}
|
||||||
$(id).append(a)
|
$(id).append(a)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
var recorder
|
var recorder
|
||||||
|
|
||||||
function done() {
|
function done() {
|
||||||
if (recorder) {
|
if (recorder) {
|
||||||
recorder.stop()
|
recorder.stop()
|
||||||
recorder.recording(function(data) {
|
recorder.recording(function(data) {
|
||||||
@@ -667,18 +744,19 @@ function SafeChat() {
|
|||||||
abort()
|
abort()
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function abort() {
|
function abort() {
|
||||||
if (recorder) {
|
if (recorder) {
|
||||||
$("#videorecorder").hide()
|
$("#videorecorder").hide()
|
||||||
recorder.release()
|
recorder.release()
|
||||||
delete recorder recorder = null
|
delete recorder
|
||||||
}
|
recorder = null
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Record Video from builtin camera
|
/// Record Video from builtin camera
|
||||||
function recordvideo() {
|
function recordvideo() {
|
||||||
try {
|
try {
|
||||||
abort()
|
abort()
|
||||||
$("#videorecorder").show()
|
$("#videorecorder").show()
|
||||||
@@ -701,9 +779,9 @@ function SafeChat() {
|
|||||||
console.log(e)
|
console.log(e)
|
||||||
error("cannot access camera", true)
|
error("cannot access camera", true)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function previewfile(content, type, name) {
|
function previewfile(content, type, name) {
|
||||||
if (!name) name = guessfilename(type)
|
if (!name) name = guessfilename(type)
|
||||||
if (type.match('^image/')) {
|
if (type.match('^image/')) {
|
||||||
var img = document.createElement("img")
|
var img = document.createElement("img")
|
||||||
@@ -748,16 +826,16 @@ function SafeChat() {
|
|||||||
img.title = name+"\n"+size(content.length)
|
img.title = name+"\n"+size(content.length)
|
||||||
$("#preview").append(img)
|
$("#preview").append(img)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Upload Attachment
|
/// Upload Attachment
|
||||||
/** Prepares attachment to be sent in a message. If the attachment is
|
/** Prepares attachment to be sent in a message. If the attachment is
|
||||||
an image, it resizes the image to 400px on the lager side.
|
an image, it resizes the image to 400px on the lager side.
|
||||||
|
|
||||||
By now, only images are supported.
|
By now, only images are supported.
|
||||||
|
|
||||||
Stores data in global variable @ref filecontent. */
|
Stores data in global variable @ref filecontent. */
|
||||||
function fileupload(evt) {
|
function fileupload(evt) {
|
||||||
if (!window.FileReader)
|
if (!window.FileReader)
|
||||||
return error("your browser does not support file upload", true)
|
return error("your browser does not support file upload", true)
|
||||||
for (var i=0, f; f=evt.target.files[i]; ++i) {
|
for (var i=0, f; f=evt.target.files[i]; ++i) {
|
||||||
@@ -771,21 +849,21 @@ function SafeChat() {
|
|||||||
}
|
}
|
||||||
reader.readAsDataURL(file)
|
reader.readAsDataURL(file)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Sets Receiver's Name
|
/// Sets Receiver's Name
|
||||||
/** Called when clicked on a receiver's name. Sets focus to the
|
/** Called when clicked on a receiver's name. Sets focus to the
|
||||||
message text field.
|
message text field.
|
||||||
|
|
||||||
@param name The receiver's name. */
|
@param name The receiver's name. */
|
||||||
function setreceiver(name) {
|
function setreceiver(name) {
|
||||||
$("#recv").val(name)
|
$("#recv").val(name)
|
||||||
checkpartner(name)
|
checkpartner(name)
|
||||||
$("#msg").focus()
|
$("#msg").focus()
|
||||||
}
|
}
|
||||||
|
|
||||||
var userMap = null
|
var userMap = null
|
||||||
function users(userlist) {
|
function users(userlist) {
|
||||||
console.log("rcv-> users")
|
console.log("rcv-> users")
|
||||||
userMap = new Array()
|
userMap = new Array()
|
||||||
$("#allusers").empty()
|
$("#allusers").empty()
|
||||||
@@ -796,9 +874,9 @@ function SafeChat() {
|
|||||||
console.log(" user: "+usr.name)
|
console.log(" user: "+usr.name)
|
||||||
})
|
})
|
||||||
localStorage.userMap = JSON.stringify(userMap)
|
localStorage.userMap = JSON.stringify(userMap)
|
||||||
}
|
}
|
||||||
|
|
||||||
function user(usr) {
|
function user(usr) {
|
||||||
if (usr.exists) console.log("rcv-> user("+usr.name+")")
|
if (usr.exists) console.log("rcv-> user("+usr.name+")")
|
||||||
else console.log("rcv-> user("+usr.name+"): name is available")
|
else console.log("rcv-> user("+usr.name+"): name is available")
|
||||||
if ($("#newuser").is(":visible") && usr.name==uid($('#user').val())) {
|
if ($("#newuser").is(":visible") && usr.name==uid($('#user').val())) {
|
||||||
@@ -831,35 +909,35 @@ function SafeChat() {
|
|||||||
$("#allusers").append('option value="'+htmlenc(usr.name)+'"')
|
$("#allusers").append('option value="'+htmlenc(usr.name)+'"')
|
||||||
localStorage.userMap = JSON.stringify(userMap)
|
localStorage.userMap = JSON.stringify(userMap)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function queryuser(usr) {
|
function queryuser(usr) {
|
||||||
console.log("query user: "+uid(usr))
|
console.log("query user: "+uid(usr))
|
||||||
socket.emit("user", uid(usr))
|
socket.emit("user", uid(usr))
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Get a user's public key.
|
/// Get a user's public key.
|
||||||
/** The first time, gets it from the server, later from the cache. */
|
/** The first time, gets it from the server, later from the cache. */
|
||||||
function getPublicKey(user) {
|
function getPublicKey(user) {
|
||||||
var deferredObject = $.Deferred()
|
var deferredObject = $.Deferred()
|
||||||
if (userMap && userMap[user]) deferredObject.resolve(userMap[user])
|
if (userMap && userMap[user]) deferredObject.resolve(userMap[user])
|
||||||
else deferredObject.reject("unknown user")
|
else deferredObject.reject("unknown user")
|
||||||
return deferredObject.promise()
|
return deferredObject.promise()
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Received a list of messages from server
|
/// Received a list of messages from server
|
||||||
function messages(msgs) {
|
function messages(msgs) {
|
||||||
console.log("rcv-> messages("+msgs.length+")")
|
console.log("rcv-> messages("+msgs.length+")")
|
||||||
if (!password || !privateKey())
|
if (!password || !privateKey())
|
||||||
return setTimeout(function() {emit("messages")}, 1000) // try again later
|
return setTimeout(function() {emit("messages")}, 1000) // try again later
|
||||||
status("allmessages")
|
show("allmessages")
|
||||||
notice("load messages, please wait …")
|
notice("load messages, please wait …")
|
||||||
msgs.forEach(function(msg) {message(msg, true)})
|
msgs.forEach(function(msg) {message(msg, true)})
|
||||||
status("chat")
|
show("chat")
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Received a message from server
|
/// Received a message from server
|
||||||
function message(m, internal) {
|
function message(m, internal) {
|
||||||
if (!internal) console.log("rcv-> message("+m.user+")")
|
if (!internal) console.log("rcv-> message("+m.user+")")
|
||||||
if (!password || !privateKey()) return
|
if (!password || !privateKey()) return
|
||||||
var key=openpgp.key.readArmored(m.pubkey)
|
var key=openpgp.key.readArmored(m.pubkey)
|
||||||
@@ -905,12 +983,13 @@ function SafeChat() {
|
|||||||
// not for me
|
// not for me
|
||||||
success()
|
success()
|
||||||
})
|
})
|
||||||
}
|
})
|
||||||
|
}
|
||||||
|
|
||||||
/// Send Message To Server
|
/// Send Message To Server
|
||||||
/** User wants to send a message. Encrypt message with own private and
|
/** User wants to send a message. Encrypt message with own private and
|
||||||
the receiver's public key, then send it to the server. */
|
the receiver's public key, then send it to the server. */
|
||||||
function sendmessage(recv, txt) {
|
function sendmessage(recv, txt) {
|
||||||
notice("1/3 preparing message …")
|
notice("1/3 preparing message …")
|
||||||
$("#message").prop(":disabled", true)
|
$("#message").prop(":disabled", true)
|
||||||
getPublicKey(recv) // get receiver's public key
|
getPublicKey(recv) // get receiver's public key
|
||||||
@@ -943,15 +1022,15 @@ function SafeChat() {
|
|||||||
$("#message").prop(":disabled", false)
|
$("#message").prop(":disabled", false)
|
||||||
error("user not found", true)
|
error("user not found", true)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Check And Set Password
|
/// Check And Set Password
|
||||||
/** Check if given password matches to decrypt the private key. If so,
|
/** Check if given password matches to decrypt the private key. If so,
|
||||||
store it in global temporary variable @ref password and start the
|
store it in global temporary variable @ref password and start the
|
||||||
chat. The password matches, when the private key can be decrypted.
|
chat. The password matches, when the private key can be decrypted.
|
||||||
|
|
||||||
@param pwd The password to check. */
|
@param pwd The password to check. */
|
||||||
function setpw(pwd) {
|
function setpw(pwd) {
|
||||||
if (privateKey().keys[0].decrypt(pwd)) {
|
if (privateKey().keys[0].decrypt(pwd)) {
|
||||||
success("password matches")
|
success("password matches")
|
||||||
$("#removeKey").hide()
|
$("#removeKey").hide()
|
||||||
@@ -960,48 +1039,48 @@ function SafeChat() {
|
|||||||
} else {
|
} else {
|
||||||
notice("password does not match")
|
notice("password does not match")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Create Password Entry Field
|
/// Create Password Entry Field
|
||||||
/** Asks user for password. When user starts to enter it, it is
|
/** Asks user for password. When user starts to enter it, it is
|
||||||
permanentely checked in setpw(). As soon as the password matches,
|
permanentely checked in setpw(). As soon as the password matches,
|
||||||
setpw() continues automatically. No submit is required by the
|
setpw() continues automatically. No submit is required by the
|
||||||
user. */
|
user. */
|
||||||
function getpwd() {
|
function getpwd() {
|
||||||
if (password) return
|
if (password) return
|
||||||
$("#removeKey").show()
|
$("#removeKey").show()
|
||||||
status("getpwd")
|
show("getpwd")
|
||||||
}
|
}
|
||||||
|
|
||||||
function deleteUser() {
|
function deleteUser() {
|
||||||
var uid = userid()
|
var uid = userid()
|
||||||
localStorage.removeItem(pubkey)
|
localStorage.removeItem(pubkey)
|
||||||
localStorage.removeItem(privkey)
|
localStorage.removeItem(privkey)
|
||||||
error("user "+uid+" permanentely lost")
|
error("user "+uid+" permanentely lost")
|
||||||
}
|
}
|
||||||
|
|
||||||
function removeKey() {
|
function removeKey() {
|
||||||
togglemenu()
|
togglemenu()
|
||||||
$("#removeKey").hide()
|
$("#removeKey").hide()
|
||||||
status('forgotpassword')
|
show('forgotpassword')
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Main Chat Window
|
/// Main Chat Window
|
||||||
/** Gets chat widgets from server and displays them. Starts timer for
|
/** Gets chat widgets from server and displays them. Starts timer for
|
||||||
get() which polls for new messages. */
|
get() which polls for new messages. */
|
||||||
var firsttime = true
|
var firsttime = true
|
||||||
function chat() {
|
function chat() {
|
||||||
if (!password) return getpwd()
|
if (!password) return getpwd()
|
||||||
status("chat")
|
show("chat")
|
||||||
if (firsttime && $('#msgs').is(':empty')) {
|
if (firsttime && $('#msgs').is(':empty')) {
|
||||||
firsttime = false
|
firsttime = false
|
||||||
notice("getting previous messages, please wait …")
|
notice("getting previous messages, please wait …")
|
||||||
emit("messages")
|
emit("messages")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Login User
|
/// Login User
|
||||||
/** This is not really a login, it is just some kind of validation.
|
/** This is not really a login, it is just some kind of validation.
|
||||||
The server does not care if a user is online or not, it is only
|
The server does not care if a user is online or not, it is only
|
||||||
interesting to the client to make sure, everything is fine. User
|
interesting to the client to make sure, everything is fine. User
|
||||||
is logged in the following way: User name and public key are sent
|
is logged in the following way: User name and public key are sent
|
||||||
@@ -1011,39 +1090,39 @@ function SafeChat() {
|
|||||||
server, it is created now. If user exists, but public key is
|
server, it is created now. If user exists, but public key is
|
||||||
different, then this is a complete failure, something went
|
different, then this is a complete failure, something went
|
||||||
terribly wrong. */
|
terribly wrong. */
|
||||||
function login() {
|
function login() {
|
||||||
$("#username").html(userid()+"@"+hostname)
|
$("#username").html(userid()+"@"+hostname)
|
||||||
emit("login", {name: userid(),
|
emit("login", {name: userid(),
|
||||||
pubkey: localStorage.pubkey})
|
pubkey: localStorage.pubkey})
|
||||||
success("login sent to server")
|
success("login sent to server")
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Get And Display Form To Create New User
|
/// Get And Display Form To Create New User
|
||||||
/** Shows user creation form. On submit, a private key is generated in
|
/** Shows user creation form. On submit, a private key is generated in
|
||||||
createkeypair(), then login() creates the user. */
|
createkeypair(), then login() creates the user. */
|
||||||
function newuser() {
|
function newuser() {
|
||||||
status("newuser")
|
show("newuser")
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Check if local storage is available
|
/// Check if local storage is available
|
||||||
function checkLocalStorage() {
|
function checkLocalStorage() {
|
||||||
var test = 'test'
|
var test = 'test'
|
||||||
try {
|
try {
|
||||||
localStorage.setItem(test, test)
|
localStorage.setItem(test, test)
|
||||||
localStorage.removeItem(test)
|
localStorage.removeItem(test)
|
||||||
return true
|
return true
|
||||||
} catch(e) {
|
} catch(e) {
|
||||||
status("nolocalstorage")
|
show("nolocalstorage")
|
||||||
error("local storage not available")
|
error("local storage not available")
|
||||||
}
|
}
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Initial Function: Startup
|
/// Initial Function: Startup
|
||||||
/** Decide whether to login or to create a new user */
|
/** Decide whether to login or to create a new user */
|
||||||
function start() {
|
function start() {
|
||||||
$("#menu").hide()
|
$("#menu").hide()
|
||||||
//status("startup")
|
//show("startup")
|
||||||
if (checkLocalStorage())
|
if (checkLocalStorage())
|
||||||
try {
|
try {
|
||||||
if (!userid()) {
|
if (!userid()) {
|
||||||
@@ -1055,9 +1134,15 @@ function SafeChat() {
|
|||||||
console.log(m.stack)
|
console.log(m.stack)
|
||||||
error(m)
|
error(m)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function init() {
|
var safechat = new SafeChat()
|
||||||
|
|
||||||
|
function init() {
|
||||||
|
safechat.start()
|
||||||
|
}
|
||||||
|
|
||||||
|
function old() {
|
||||||
/// On Load, Call @ref start
|
/// On Load, Call @ref start
|
||||||
$(window.onbeforeunload = function() {
|
$(window.onbeforeunload = function() {
|
||||||
return "Are you sure you want to navigate away?"
|
return "Are you sure you want to navigate away?"
|
||||||
@@ -1075,7 +1160,7 @@ function SafeChat() {
|
|||||||
console.log("asynchronous openpgp failed")
|
console.log("asynchronous openpgp failed")
|
||||||
emit('users')
|
emit('users')
|
||||||
start()
|
start()
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Start Main Loop
|
/// Start Main Loop
|
||||||
$(init)
|
$(init)
|
||||||
|
|||||||
@@ -58,7 +58,7 @@ form input#msg {
|
|||||||
height: 1.5em;
|
height: 1.5em;
|
||||||
}
|
}
|
||||||
.toolbutton input {
|
.toolbutton input {
|
||||||
display:none;
|
display: none;
|
||||||
}
|
}
|
||||||
.toolbutton.bad:first-line,
|
.toolbutton.bad:first-line,
|
||||||
.toolbutton.good:first-line {
|
.toolbutton.good:first-line {
|
||||||
|
|||||||
+15
-2
@@ -79,7 +79,7 @@ module.exports = function(sql) {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
socket.on("user", function(name) {
|
socket.on("user", function(name, fn) {
|
||||||
console.log("-> signal: user("+name+")");
|
console.log("-> signal: user("+name+")");
|
||||||
var result = {name: name, exists: false, pubkey: null};
|
var result = {name: name, exists: false, pubkey: null};
|
||||||
sql.query("select pubkey from user where name = ?", [name], function(err, res, flds) {
|
sql.query("select pubkey from user where name = ?", [name], function(err, res, flds) {
|
||||||
@@ -87,7 +87,20 @@ module.exports = function(sql) {
|
|||||||
result.exists = true;
|
result.exists = true;
|
||||||
result.pubkey = res[0].pubkey;
|
result.pubkey = res[0].pubkey;
|
||||||
}
|
}
|
||||||
emit('user', result);
|
fn(result);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
socket.on("lookup", function(name, fn) {
|
||||||
|
console.log("-> signal: lookup("+name+")")
|
||||||
|
var result = false
|
||||||
|
sql.query("select pubkey from user where name = ?",
|
||||||
|
[name],
|
||||||
|
function(err, res, flds) {
|
||||||
|
if (!err && res && res.length) {
|
||||||
|
result = true;
|
||||||
|
}
|
||||||
|
fn(result)
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
+7
-16
@@ -51,21 +51,12 @@
|
|||||||
<div id="newuser" style="display: none">
|
<div id="newuser" style="display: none">
|
||||||
<h2>Register User</h2>
|
<h2>Register User</h2>
|
||||||
<p>All you need to start is a username and a password:</p>
|
<p>All you need to start is a username and a password:</p>
|
||||||
<form id="register" autocomplete="off">
|
<form id="register" autocomplete="off" onsubmit="safechat.createuser(document.getElementById('user').value, document.getElementById('pwd').value)">
|
||||||
<input placeholder="username" autocomplete="off" type="text" id="user"/>
|
<input placeholder="username" autocomplete="off" type="text" id="user" oninput="safechat.lookup(this.value)" />
|
||||||
<input placeholder="password" autocomplete="off" type="password" id="pwd" oninput="checkpwd(this.value, document.getElementById('pwd2').value)"/>
|
<input placeholder="password" autocomplete="off" type="password" id="pwd" oninput="safechat.checkpasswords(this.value, document.getElementById('pwd2').value)"/>
|
||||||
<input placeholder="repeat password" autocomplete="off" type="password" id="pwd2" oninput="checkpwd(document.getElementById('pwd').value, this.value)"/>
|
<input placeholder="repeat password" autocomplete="off" type="password" id="pwd2" oninput="safechat.checkpasswords(document.getElementById('pwd').value, this.value)"/>
|
||||||
<button id="createuser" disabled>register</button>
|
<input id="createuser" type="submit" value="register" disabled />
|
||||||
</form>
|
</form>
|
||||||
<script>
|
|
||||||
$("#user").on("input", function() {
|
|
||||||
queryuser($('#user').val());
|
|
||||||
});
|
|
||||||
$("#createuser").on("click", function(event) {
|
|
||||||
createkeypair($('#user').val(), $('#pwd').val());
|
|
||||||
return false;
|
|
||||||
});
|
|
||||||
</script>
|
|
||||||
<p>Please chose any username, e.g. a pseudonym, your e-mail,
|
<p>Please chose any username, e.g. a pseudonym, your e-mail,
|
||||||
your phone number, your real name, and chose a safe
|
your phone number, your real name, and chose a safe
|
||||||
password.</p>
|
password.</p>
|
||||||
@@ -184,9 +175,9 @@
|
|||||||
|
|
||||||
<!-- Fatal: Abort -->
|
<!-- Fatal: Abort -->
|
||||||
|
|
||||||
<div id="fatal">
|
<div id="fatal" style="display: none">
|
||||||
<h2 id="fatal-msg">Failure</h2>
|
<h2 id="fatal-msg">Failure</h2>
|
||||||
<p>The SafeChat has been aborted due to a fatal error.</p>
|
<p>SafeChat has been aborted due to a fatal error.</p>
|
||||||
<p>There is a problem in your browser. Please try to reload. If the problem persists, please update your web browser or try SafeChat in another browser.</p>
|
<p>There is a problem in your browser. Please try to reload. If the problem persists, please update your web browser or try SafeChat in another browser.</p>
|
||||||
<p>The following java script features are required:</p>
|
<p>The following java script features are required:</p>
|
||||||
<ul class="features">
|
<ul class="features">
|
||||||
|
|||||||
Reference in New Issue
Block a user