Refactored converse-otr.js
- Removed password encryption of the key. It never properly worked and bloated the build through extra dependencies. - Store the key and instance tag on the ChatBox model.
This commit is contained in:
parent
fd97edf4f5
commit
ba9d3c36d5
@ -6,7 +6,6 @@
|
||||
"devDependencies": {
|
||||
"bootstrap": "~3.2.0",
|
||||
"bourbon": "~4.2.6",
|
||||
"crypto-js-evanvosberg": "https://github.com/evanvosberg/crypto-js.git#release-3.1.2-5",
|
||||
"fontawesome": "~4.1.0"
|
||||
},
|
||||
"dependencies": {},
|
||||
|
15
config.js
15
config.js
@ -67,21 +67,8 @@ require.config({
|
||||
"converse-vcard": "src/converse-vcard",
|
||||
|
||||
// Off-the-record-encryption
|
||||
"bigint": "node_modules/otr/vendor/bigint",
|
||||
"bigint": "node_modules/otr/build/dep/bigint",
|
||||
"crypto": "node_modules/otr/build/dep/crypto",
|
||||
"aes": "node_modules/crypto-js/aes",
|
||||
"cipher-core": "node_modules/crypto-js/cipher-core",
|
||||
"core": "node_modules/crypto-js/core",
|
||||
"const": "node_modules/otr/lib/const",
|
||||
"helpers": "node_modules/otr/lib/helpers",
|
||||
"sha1": "node_modules/crypto-js/sha1",
|
||||
"hmac": "node_modules/crypto-js/hmac",
|
||||
"enc-base64": "node_modules/crypto-js/enc-base64",
|
||||
"evpkdf": "node_modules/crypto-js/evpkdf",
|
||||
"md5": "node_modules/crypto-js/md5",
|
||||
"mode-ctr": "node_modules/crypto-js/mode-ctr",
|
||||
"pad-nopadding": "node_modules/crypto-js/pad-nopadding",
|
||||
"sha256": "node_modules/crypto-js/sha256",
|
||||
"salsa20": "node_modules/otr/build/dep/salsa20",
|
||||
"otr": "node_modules/otr/build/otr",
|
||||
|
||||
|
@ -39,7 +39,6 @@
|
||||
"backbone.overview": "0.0.3",
|
||||
"bower": "latest",
|
||||
"clean-css": "^3.4.19",
|
||||
"crypto-js": "3.1.2-5",
|
||||
"eslint": "^3.14.1",
|
||||
"eslint-plugin-lodash": "^2.3.3",
|
||||
"greenkeeper": "^4.1.0",
|
||||
|
25
spec/otr.js
25
spec/otr.js
@ -7,31 +7,6 @@
|
||||
|
||||
return describe("The OTR module", function() {
|
||||
|
||||
it("can store a session passphrase in session storage", mock.initConverse(function (_converse) {
|
||||
// With no prebind, the user's XMPP password is used and nothing is
|
||||
// stored in session storage.
|
||||
test_utils.openControlBox();
|
||||
test_utils.openContactsPanel(_converse);
|
||||
test_utils.createContacts(_converse, 'current');
|
||||
|
||||
var auth = _converse.authentication;
|
||||
var pass = _converse.connection.pass;
|
||||
_converse.authentication = "manual";
|
||||
_converse.connection.pass = 's3cr3t!';
|
||||
expect(_converse.otr.getSessionPassphrase()).toBe(_converse.connection.pass);
|
||||
|
||||
// With prebind, a random passphrase is generated and stored in
|
||||
// session storage.
|
||||
_converse.authentication = "prebind";
|
||||
var pp = _converse.otr.getSessionPassphrase();
|
||||
expect(pp).not.toBe(_converse.connection.pass);
|
||||
expect(pp).toBe(window.sessionStorage[b64_sha1(_converse.connection.jid)]);
|
||||
|
||||
// Clean up
|
||||
_converse.authentication = auth;
|
||||
_converse.connection.pass = pass;
|
||||
}));
|
||||
|
||||
it("will add processing hints to sent out encrypted <message> stanzas", mock.initConverse(function (_converse) {
|
||||
test_utils.openControlBox();
|
||||
test_utils.openContactsPanel(_converse);
|
||||
|
@ -13,11 +13,9 @@
|
||||
|
||||
define(["converse-chatview",
|
||||
"tpl!toolbar_otr",
|
||||
'otr',
|
||||
'crypto',
|
||||
'aes'
|
||||
'otr'
|
||||
], factory);
|
||||
}(this, function (converse, tpl_toolbar_otr, otr, CryptoJS) {
|
||||
}(this, function (converse, tpl_toolbar_otr, otr) {
|
||||
"use strict";
|
||||
|
||||
// Strophe methods for building stanzas
|
||||
@ -33,7 +31,6 @@
|
||||
));
|
||||
|
||||
var HAS_CRYPTO = HAS_CSPRNG && (
|
||||
(!_.isUndefined(CryptoJS)) &&
|
||||
(!_.isUndefined(otr.OTR)) &&
|
||||
(!_.isUndefined(otr.DSA))
|
||||
);
|
||||
@ -59,14 +56,8 @@
|
||||
//
|
||||
// New functions which don't exist yet can also be added.
|
||||
|
||||
_initialize: function () {
|
||||
this.__super__._initialize.apply(this, arguments);
|
||||
this.otr = new this.OTR();
|
||||
},
|
||||
|
||||
registerGlobalEventHandlers: function () {
|
||||
this.__super__.registerGlobalEventHandlers();
|
||||
|
||||
$(document).click(function () {
|
||||
if ($('.toggle-otr ul').is(':visible')) {
|
||||
$('.toggle-otr ul', this).slideUp();
|
||||
@ -81,9 +72,7 @@
|
||||
initialize: function () {
|
||||
this.__super__.initialize.apply(this, arguments);
|
||||
if (this.get('box_id') !== 'controlbox') {
|
||||
this.save({
|
||||
'otr_status': this.get('otr_status') || UNENCRYPTED
|
||||
});
|
||||
this.save({'otr_status': this.get('otr_status') || UNENCRYPTED});
|
||||
}
|
||||
},
|
||||
|
||||
@ -123,31 +112,34 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
generatePrivateKey: function (instance_tag) {
|
||||
var _converse = this.__super__._converse;
|
||||
var key = new otr.DSA();
|
||||
var jid = _converse.connection.jid;
|
||||
if (_converse.cache_otr_key) {
|
||||
this.save({
|
||||
'otr_priv_key': key.packPrivate(),
|
||||
'otr_instance_tag': instance_tag
|
||||
});
|
||||
}
|
||||
return key;
|
||||
},
|
||||
|
||||
getSession: function (callback) {
|
||||
var _converse = this.__super__._converse,
|
||||
__ = _converse.__;
|
||||
var cipher = CryptoJS.lib.PasswordBasedCipher;
|
||||
var pass, instance_tag, saved_key, pass_check;
|
||||
var instance_tag, saved_key;
|
||||
if (_converse.cache_otr_key) {
|
||||
pass = _converse.otr.getSessionPassphrase();
|
||||
if (!_.isUndefined(pass)) {
|
||||
instance_tag = window.sessionStorage[b64_sha1(this.id+'instance_tag')];
|
||||
saved_key = window.sessionStorage[b64_sha1(this.id+'priv_key')];
|
||||
pass_check = window.sessionStorage[b64_sha1(this.connection.jid+'pass_check')];
|
||||
if (saved_key && instance_tag && !_.isUndefined(pass_check)) {
|
||||
var decrypted = cipher.decrypt(CryptoJS.algo.AES, saved_key, pass);
|
||||
var key = otr.DSA.parsePrivate(decrypted.toString(CryptoJS.enc.Latin1));
|
||||
if (cipher.decrypt(CryptoJS.algo.AES, pass_check, pass).toString(CryptoJS.enc.Latin1) === 'match') {
|
||||
// Verified that the passphrase is still the same
|
||||
this.trigger('showHelpMessages', [__('Re-establishing encrypted session')]);
|
||||
callback({
|
||||
'key': key,
|
||||
'instance_tag': instance_tag
|
||||
});
|
||||
return; // Our work is done here
|
||||
}
|
||||
}
|
||||
instance_tag = this.get('otr_instance_tag');
|
||||
saved_key = otr.DSA.parsePrivate(this.get('otr_priv_key'));
|
||||
if (saved_key && instance_tag) {
|
||||
this.trigger('showHelpMessages', [__('Re-establishing encrypted session')]);
|
||||
callback({
|
||||
'key': saved_key,
|
||||
'instance_tag': instance_tag
|
||||
});
|
||||
return; // Our work is done here
|
||||
}
|
||||
}
|
||||
// We need to generate a new key and instance tag
|
||||
@ -157,10 +149,11 @@
|
||||
null,
|
||||
true // show spinner
|
||||
);
|
||||
var that = this;
|
||||
window.setTimeout(function () {
|
||||
var instance_tag = otr.OTR.makeInstanceTag();
|
||||
callback({
|
||||
'key': _converse.otr.generatePrivateKey.call(this, instance_tag),
|
||||
'key': that.generatePrivateKey(instance_tag),
|
||||
'instance_tag': instance_tag
|
||||
});
|
||||
}, 500);
|
||||
@ -466,6 +459,12 @@
|
||||
var _converse = this._converse,
|
||||
__ = _converse.__;
|
||||
|
||||
this.updateSettings({
|
||||
allow_otr: true,
|
||||
cache_otr_key: false,
|
||||
use_otr_by_default: false
|
||||
});
|
||||
|
||||
// Add new HTML template
|
||||
_converse.templates.toolbar_otr = tpl_toolbar_otr;
|
||||
|
||||
@ -480,59 +479,10 @@
|
||||
OTR_TRANSLATED_MAPPING[VERIFIED] = __('verified');
|
||||
OTR_TRANSLATED_MAPPING[FINISHED] = __('finished');
|
||||
|
||||
// For translations
|
||||
__ = utils.__.bind(_converse);
|
||||
// Configuration values for this plugin
|
||||
var settings = {
|
||||
allow_otr: true,
|
||||
cache_otr_key: false,
|
||||
use_otr_by_default: false
|
||||
};
|
||||
_.extend(_converse.default_settings, settings);
|
||||
_.extend(_converse, settings);
|
||||
_.extend(_converse, _.pick(_converse.user_settings, _.keys(settings)));
|
||||
|
||||
// Only allow OTR if we have the capability
|
||||
_converse.allow_otr = _converse.allow_otr && HAS_CRYPTO;
|
||||
// Only use OTR by default if allow OTR is enabled to begin with
|
||||
_converse.use_otr_by_default = _converse.use_otr_by_default && _converse.allow_otr;
|
||||
|
||||
// Backbone Models and Views
|
||||
// -------------------------
|
||||
_converse.OTR = Backbone.Model.extend({
|
||||
// A model for managing OTR settings.
|
||||
getSessionPassphrase: function () {
|
||||
if (_converse.authentication === 'prebind') {
|
||||
var key = b64_sha1(_converse.connection.jid),
|
||||
pass = window.sessionStorage[key];
|
||||
if (_.isUndefined(pass)) {
|
||||
pass = Math.floor(Math.random()*4294967295).toString();
|
||||
window.sessionStorage[key] = pass;
|
||||
}
|
||||
return pass;
|
||||
} else {
|
||||
return _converse.connection.pass;
|
||||
}
|
||||
},
|
||||
|
||||
generatePrivateKey: function (instance_tag) {
|
||||
var key = new otr.DSA();
|
||||
var jid = _converse.connection.jid;
|
||||
if (_converse.cache_otr_key) {
|
||||
var cipher = CryptoJS.lib.PasswordBasedCipher;
|
||||
var pass = this.getSessionPassphrase();
|
||||
if (!_.isUndefined(pass)) {
|
||||
// Encrypt the key and set in sessionStorage. Also store instance tag.
|
||||
window.sessionStorage[b64_sha1(jid+'priv_key')] =
|
||||
cipher.encrypt(CryptoJS.algo.AES, key.packPrivate(), pass).toString();
|
||||
window.sessionStorage[b64_sha1(jid+'instance_tag')] = instance_tag;
|
||||
window.sessionStorage[b64_sha1(jid+'pass_check')] =
|
||||
cipher.encrypt(CryptoJS.algo.AES, 'match', pass).toString();
|
||||
}
|
||||
}
|
||||
return key;
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
}));
|
||||
|
Loading…
Reference in New Issue
Block a user