2016-02-13 23:58:50 +01:00
// Converse.js (A browser based XMPP chat client)
// http://conversejs.org
//
// Copyright (c) 2012-2016, Jan-Carel Brand <jc@opkode.com>
// Licensed under the Mozilla Public License (MPLv2)
//
2016-02-20 16:06:12 +01:00
/*global Backbone, define, window, crypto, CryptoJS */
2016-02-13 23:58:50 +01:00
/ * T h i s i s a C o n v e r s e . j s p l u g i n w h i c h a d d s u p p o r t O f f - t h e - r e c o r d ( O T R )
* encryption of one - on - one chat messages .
* /
( function ( root , factory ) {
2016-03-19 14:33:31 +01:00
define ( "converse-otr" , [
"otr" ,
"converse-core" ,
2016-09-23 10:54:55 +02:00
"converse-api" ,
"tpl!toolbar_otr"
2016-03-19 14:33:31 +01:00
] , factory ) ;
2016-09-23 10:54:55 +02:00
} ( this , function ( otr , converse , converse _api , tpl _toolbar _otr ) {
2016-02-19 11:43:46 +01:00
"use strict" ;
2016-09-23 10:54:55 +02:00
converse . templates . toolbar _otr = tpl _toolbar _otr ;
2016-02-13 23:58:50 +01:00
// Strophe methods for building stanzas
var Strophe = converse _api . env . Strophe ,
2016-02-20 16:06:12 +01:00
utils = converse _api . env . utils ,
2016-02-13 23:58:50 +01:00
b64 _sha1 = converse _api . env . b64 _sha1 ;
// Other necessary globals
var $ = converse _api . env . jQuery ,
_ = converse _api . env . _ ;
2016-02-28 09:30:07 +01:00
// For translations
var _ _ = utils . _ _ . bind ( converse ) ;
2016-02-13 23:58:50 +01:00
var HAS _CSPRNG = ( ( typeof crypto !== 'undefined' ) &&
( ( typeof crypto . randomBytes === 'function' ) ||
( typeof crypto . getRandomValues === 'function' )
) ) ;
var HAS _CRYPTO = HAS _CSPRNG && (
( typeof CryptoJS !== "undefined" ) &&
( typeof otr . OTR !== "undefined" ) &&
( typeof otr . DSA !== "undefined" )
) ;
var UNENCRYPTED = 0 ;
var UNVERIFIED = 1 ;
var VERIFIED = 2 ;
var FINISHED = 3 ;
2016-02-28 09:30:07 +01:00
var OTR _TRANSLATED _MAPPING = { } ; // Populated in initialize
2016-02-13 23:58:50 +01:00
var OTR _CLASS _MAPPING = { } ;
OTR _CLASS _MAPPING [ UNENCRYPTED ] = 'unencrypted' ;
OTR _CLASS _MAPPING [ UNVERIFIED ] = 'unverified' ;
OTR _CLASS _MAPPING [ VERIFIED ] = 'verified' ;
OTR _CLASS _MAPPING [ FINISHED ] = 'finished' ;
2016-06-09 11:01:54 +02:00
converse _api . plugins . add ( 'converse-otr' , {
2016-02-13 23:58:50 +01:00
overrides : {
// Overrides mentioned here will be picked up by converse.js's
// plugin architecture they will replace existing methods on the
// relevant objects or classes.
//
// New functions which don't exist yet can also be added.
_initialize : function ( ) {
2016-08-31 12:06:17 +02:00
this . _ _super _ _ . _initialize . apply ( this , arguments ) ;
2016-02-28 20:24:06 +01:00
this . otr = new this . OTR ( ) ;
2016-02-13 23:58:50 +01:00
} ,
registerGlobalEventHandlers : function ( ) {
2016-08-31 12:06:17 +02:00
this . _ _super _ _ . registerGlobalEventHandlers ( ) ;
2016-02-13 23:58:50 +01:00
$ ( document ) . click ( function ( ) {
if ( $ ( '.toggle-otr ul' ) . is ( ':visible' ) ) {
$ ( '.toggle-otr ul' , this ) . slideUp ( ) ;
}
if ( $ ( '.toggle-smiley ul' ) . is ( ':visible' ) ) {
$ ( '.toggle-smiley ul' , this ) . slideUp ( ) ;
}
} ) ;
} ,
wrappedChatBox : function ( chatbox ) {
2016-08-31 12:06:17 +02:00
var wrapped _chatbox = this . _ _super _ _ . wrappedChatBox . apply ( this , arguments ) ;
2016-02-13 23:58:50 +01:00
if ( ! chatbox ) { return ; }
return _ . extend ( wrapped _chatbox , {
'endOTR' : chatbox . endOTR . bind ( chatbox ) ,
'initiateOTR' : chatbox . initiateOTR . bind ( chatbox ) ,
} ) ;
} ,
ChatBox : {
initialize : function ( ) {
2016-08-31 12:06:17 +02:00
this . _ _super _ _ . initialize . apply ( this , arguments ) ;
2016-02-13 23:58:50 +01:00
if ( this . get ( 'box_id' ) !== 'controlbox' ) {
this . save ( {
'otr_status' : this . get ( 'otr_status' ) || UNENCRYPTED
} ) ;
}
} ,
2016-02-14 13:10:54 +01:00
shouldPlayNotification : function ( $message ) {
/ * D o n ' t p l a y a n o t i f i c a t i o n i f t h i s i s a n O T R m e s s a g e b u t
* encryption is not yet set up . That would mean that the
* OTR session is still being established , so there are no
* "visible" OTR messages being exchanged .
* /
2016-08-31 12:06:17 +02:00
return this . _ _super _ _ . shouldPlayNotification . apply ( this , arguments ) &&
2016-05-30 20:19:10 +02:00
! ( utils . isOTRMessage ( $message [ 0 ] ) && ! _ . contains ( [ UNVERIFIED , VERIFIED ] , this . get ( 'otr_status' ) ) ) ;
2016-02-14 13:10:54 +01:00
} ,
2016-05-30 18:17:26 +02:00
createMessage : function ( $message , $delay , original _stanza ) {
2016-08-31 12:06:17 +02:00
var converse = this . _ _super _ _ . converse ,
2016-02-14 13:10:54 +01:00
$body = $message . children ( 'body' ) ,
text = ( $body . length > 0 ? $body . text ( ) : undefined ) ;
2016-02-13 23:58:50 +01:00
if ( ( ! text ) || ( ! converse . allow _otr ) ) {
2016-08-31 12:06:17 +02:00
return this . _ _super _ _ . createMessage . apply ( this , arguments ) ;
2016-02-13 23:58:50 +01:00
}
if ( text . match ( /^\?OTRv23?/ ) ) {
this . initiateOTR ( text ) ;
} else {
if ( _ . contains ( [ UNVERIFIED , VERIFIED ] , this . get ( 'otr_status' ) ) ) {
this . otr . receiveMsg ( text ) ;
} else {
if ( text . match ( /^\?OTR/ ) ) {
if ( ! this . otr ) {
this . initiateOTR ( text ) ;
} else {
this . otr . receiveMsg ( text ) ;
}
} else {
// Normal unencrypted message.
2016-08-31 12:06:17 +02:00
return this . _ _super _ _ . createMessage . apply ( this , arguments ) ;
2016-02-13 23:58:50 +01:00
}
}
}
} ,
getSession : function ( callback ) {
2016-08-31 12:06:17 +02:00
var converse = this . _ _super _ _ . converse ;
2016-02-13 23:58:50 +01:00
var cipher = CryptoJS . lib . PasswordBasedCipher ;
var pass , instance _tag , saved _key , pass _check ;
if ( converse . cache _otr _key ) {
pass = converse . otr . getSessionPassphrase ( ) ;
if ( typeof pass !== "undefined" ) {
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 && typeof pass _check !== 'undefined' ) {
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
}
}
}
}
// We need to generate a new key and instance tag
this . trigger ( 'showHelpMessages' , [
_ _ ( 'Generating private key.' ) ,
_ _ ( 'Your browser might become unresponsive.' ) ] ,
null ,
true // show spinner
) ;
2016-02-20 16:06:12 +01:00
window . setTimeout ( function ( ) {
2016-02-13 23:58:50 +01:00
var instance _tag = otr . OTR . makeInstanceTag ( ) ;
callback ( {
'key' : converse . otr . generatePrivateKey . call ( this , instance _tag ) ,
'instance_tag' : instance _tag
} ) ;
} , 500 ) ;
} ,
updateOTRStatus : function ( state ) {
switch ( state ) {
case otr . OTR . CONST . STATUS _AKE _SUCCESS :
if ( this . otr . msgstate === otr . OTR . CONST . MSGSTATE _ENCRYPTED ) {
this . save ( { 'otr_status' : UNVERIFIED } ) ;
}
break ;
case otr . OTR . CONST . STATUS _END _OTR :
if ( this . otr . msgstate === otr . OTR . CONST . MSGSTATE _FINISHED ) {
this . save ( { 'otr_status' : FINISHED } ) ;
} else if ( this . otr . msgstate === otr . OTR . CONST . MSGSTATE _PLAINTEXT ) {
this . save ( { 'otr_status' : UNENCRYPTED } ) ;
}
break ;
}
} ,
onSMP : function ( type , data ) {
// Event handler for SMP (Socialist's Millionaire Protocol)
// used by OTR (off-the-record).
switch ( type ) {
case 'question' :
this . otr . smpSecret ( prompt ( _ _ (
'Authentication request from %1$s\n\nYour chat contact is attempting to verify your identity, by asking you the question below.\n\n%2$s' ,
[ this . get ( 'fullname' ) , data ] ) ) ) ;
break ;
case 'trust' :
if ( data === true ) {
this . save ( { 'otr_status' : VERIFIED } ) ;
} else {
this . trigger (
'showHelpMessages' ,
[ _ _ ( "Could not verify this user's identify." ) ] ,
'error' ) ;
this . save ( { 'otr_status' : UNVERIFIED } ) ;
}
break ;
default :
throw new TypeError ( 'ChatBox.onSMP: Unknown type for SMP' ) ;
}
} ,
initiateOTR : function ( query _msg ) {
// Sets up an OTR object through which we can send and receive
// encrypted messages.
//
// If 'query_msg' is passed in, it means there is an alread incoming
// query message from our contact. Otherwise, it is us who will
// send the query message to them.
this . save ( { 'otr_status' : UNENCRYPTED } ) ;
this . getSession ( function ( session ) {
2016-08-31 12:06:17 +02:00
var converse = this . _ _super _ _ . converse ;
2016-02-13 23:58:50 +01:00
this . otr = new otr . OTR ( {
fragment _size : 140 ,
send _interval : 200 ,
priv : session . key ,
instance _tag : session . instance _tag ,
debug : this . debug
} ) ;
this . otr . on ( 'status' , this . updateOTRStatus . bind ( this ) ) ;
this . otr . on ( 'smp' , this . onSMP . bind ( this ) ) ;
this . otr . on ( 'ui' , function ( msg ) {
this . trigger ( 'showReceivedOTRMessage' , msg ) ;
} . bind ( this ) ) ;
this . otr . on ( 'io' , function ( msg ) {
this . trigger ( 'sendMessage' , new converse . Message ( { message : msg } ) ) ;
} . bind ( this ) ) ;
this . otr . on ( 'error' , function ( msg ) {
this . trigger ( 'showOTRError' , msg ) ;
} . bind ( this ) ) ;
this . trigger ( 'showHelpMessages' , [ _ _ ( 'Exchanging private key with contact.' ) ] ) ;
if ( query _msg ) {
this . otr . receiveMsg ( query _msg ) ;
} else {
this . otr . sendQueryMsg ( ) ;
}
} . bind ( this ) ) ;
} ,
endOTR : function ( ) {
if ( this . otr ) {
this . otr . endOtr ( ) ;
}
this . save ( { 'otr_status' : UNENCRYPTED } ) ;
}
} ,
ChatBoxView : {
events : {
'click .toggle-otr' : 'toggleOTRMenu' ,
'click .start-otr' : 'startOTRFromToolbar' ,
'click .end-otr' : 'endOTR' ,
'click .auth-otr' : 'authOTR'
} ,
initialize : function ( ) {
2016-08-31 12:06:17 +02:00
var converse = this . _ _super _ _ . converse ;
this . _ _super _ _ . initialize . apply ( this , arguments ) ;
2016-02-13 23:58:50 +01:00
this . model . on ( 'change:otr_status' , this . onOTRStatusChanged , this ) ;
this . model . on ( 'showOTRError' , this . showOTRError , this ) ;
this . model . on ( 'showSentOTRMessage' , function ( text ) {
this . showMessage ( { 'message' : text , 'sender' : 'me' } ) ;
} , this ) ;
this . model . on ( 'showReceivedOTRMessage' , function ( text ) {
this . showMessage ( { 'message' : text , 'sender' : 'them' } ) ;
} , this ) ;
if ( ( _ . contains ( [ UNVERIFIED , VERIFIED ] , this . model . get ( 'otr_status' ) ) ) || converse . use _otr _by _default ) {
this . model . initiateOTR ( ) ;
}
} ,
createMessageStanza : function ( ) {
2016-08-31 12:06:17 +02:00
var stanza = this . _ _super _ _ . createMessageStanza . apply ( this , arguments ) ;
2016-05-30 20:19:10 +02:00
if ( this . model . get ( 'otr_status' ) !== UNENCRYPTED || utils . isOTRMessage ( stanza . nodeTree ) ) {
2016-02-13 23:58:50 +01:00
// OTR messages aren't carbon copied
2016-05-30 18:20:23 +02:00
stanza . c ( 'private' , { 'xmlns' : Strophe . NS . CARBONS } ) . up ( )
. c ( 'no-store' , { 'xmlns' : Strophe . NS . HINTS } ) . up ( )
. c ( 'no-permanent-store' , { 'xmlns' : Strophe . NS . HINTS } ) . up ( )
. c ( 'no-copy' , { 'xmlns' : Strophe . NS . HINTS } ) ;
2016-02-13 23:58:50 +01:00
}
return stanza ;
} ,
onMessageSubmitted : function ( text ) {
2016-08-31 12:06:17 +02:00
var converse = this . _ _super _ _ . converse ;
2016-02-13 23:58:50 +01:00
if ( ! converse . connection . authenticated ) {
return this . showHelpMessages (
[ 'Sorry, the connection has been lost, ' +
'and your message could not be sent' ] ,
'error'
) ;
}
var match = text . replace ( /^\s*/ , "" ) . match ( /^\/(.*)\s*$/ ) ;
if ( match ) {
if ( ( converse . allow _otr ) && ( match [ 1 ] === "endotr" ) ) {
return this . endOTR ( ) ;
} else if ( ( converse . allow _otr ) && ( match [ 1 ] === "otr" ) ) {
return this . model . initiateOTR ( ) ;
}
}
if ( _ . contains ( [ UNVERIFIED , VERIFIED ] , this . model . get ( 'otr_status' ) ) ) {
// Off-the-record encryption is active
this . model . otr . sendMsg ( text ) ;
this . model . trigger ( 'showSentOTRMessage' , text ) ;
} else {
2016-08-31 12:06:17 +02:00
this . _ _super _ _ . onMessageSubmitted . apply ( this , arguments ) ;
2016-02-13 23:58:50 +01:00
}
} ,
onOTRStatusChanged : function ( ) {
this . renderToolbar ( ) . informOTRChange ( ) ;
} ,
informOTRChange : function ( ) {
var data = this . model . toJSON ( ) ;
var msgs = [ ] ;
if ( data . otr _status === UNENCRYPTED ) {
msgs . push ( _ _ ( "Your messages are not encrypted anymore" ) ) ;
} else if ( data . otr _status === UNVERIFIED ) {
msgs . push ( _ _ ( "Your messages are now encrypted but your contact's identity has not been verified." ) ) ;
} else if ( data . otr _status === VERIFIED ) {
msgs . push ( _ _ ( "Your contact's identify has been verified." ) ) ;
} else if ( data . otr _status === FINISHED ) {
msgs . push ( _ _ ( "Your contact has ended encryption on their end, you should do the same." ) ) ;
}
return this . showHelpMessages ( msgs , 'info' , false ) ;
} ,
showOTRError : function ( msg ) {
2016-08-31 12:06:17 +02:00
var converse = this . _ _super _ _ . converse ;
2016-02-13 23:58:50 +01:00
if ( msg === 'Message cannot be sent at this time.' ) {
this . showHelpMessages (
[ _ _ ( 'Your message could not be sent' ) ] , 'error' ) ;
} else if ( msg === 'Received an unencrypted message.' ) {
this . showHelpMessages (
[ _ _ ( 'We received an unencrypted message' ) ] , 'error' ) ;
} else if ( msg === 'Received an unreadable encrypted message.' ) {
this . showHelpMessages (
[ _ _ ( 'We received an unreadable encrypted message' ) ] ,
'error' ) ;
} else {
this . showHelpMessages ( [ 'Encryption error occured: ' + msg ] , 'error' ) ;
}
converse . log ( "OTR ERROR:" + msg ) ;
} ,
startOTRFromToolbar : function ( ev ) {
$ ( ev . target ) . parent ( ) . parent ( ) . slideUp ( ) ;
ev . stopPropagation ( ) ;
this . model . initiateOTR ( ) ;
} ,
endOTR : function ( ev ) {
if ( typeof ev !== "undefined" ) {
ev . preventDefault ( ) ;
ev . stopPropagation ( ) ;
}
this . model . endOTR ( ) ;
} ,
authOTR : function ( ev ) {
2016-08-31 12:06:17 +02:00
var converse = this . _ _super _ _ . converse ;
2016-02-13 23:58:50 +01:00
var scheme = $ ( ev . target ) . data ( ) . scheme ;
var result , question , answer ;
if ( scheme === 'fingerprint' ) {
result = confirm ( _ _ ( 'Here are the fingerprints, please confirm them with %1$s, outside of this chat.\n\nFingerprint for you, %2$s: %3$s\n\nFingerprint for %1$s: %4$s\n\nIf you have confirmed that the fingerprints match, click OK, otherwise click Cancel.' , [
this . model . get ( 'fullname' ) ,
converse . xmppstatus . get ( 'fullname' ) || converse . bare _jid ,
this . model . otr . priv . fingerprint ( ) ,
this . model . otr . their _priv _pk . fingerprint ( )
]
) ) ;
if ( result === true ) {
this . model . save ( { 'otr_status' : VERIFIED } ) ;
} else {
this . model . save ( { 'otr_status' : UNVERIFIED } ) ;
}
} else if ( scheme === 'smp' ) {
alert ( _ _ ( 'You will be prompted to provide a security question and then an answer to that question.\n\nYour contact will then be prompted the same question and if they type the exact same answer (case sensitive), their identity will be verified.' ) ) ;
question = prompt ( _ _ ( 'What is your security question?' ) ) ;
if ( question ) {
answer = prompt ( _ _ ( 'What is the answer to the security question?' ) ) ;
this . model . otr . smpSecret ( answer , question ) ;
}
} else {
this . showHelpMessages ( [ _ _ ( 'Invalid authentication scheme provided' ) ] , 'error' ) ;
}
} ,
toggleOTRMenu : function ( ev ) {
ev . stopPropagation ( ) ;
this . $el . find ( '.toggle-otr ul' ) . slideToggle ( 200 ) ;
} ,
getOTRTooltip : function ( ) {
var data = this . model . toJSON ( ) ;
if ( data . otr _status === UNENCRYPTED ) {
return _ _ ( 'Your messages are not encrypted. Click here to enable OTR encryption.' ) ;
} else if ( data . otr _status === UNVERIFIED ) {
return _ _ ( 'Your messages are encrypted, but your contact has not been verified.' ) ;
} else if ( data . otr _status === VERIFIED ) {
return _ _ ( 'Your messages are encrypted and your contact verified.' ) ;
} else if ( data . otr _status === FINISHED ) {
return _ _ ( 'Your contact has closed their end of the private session, you should do the same' ) ;
}
} ,
2016-10-27 13:30:58 +02:00
renderToolbar : function ( toolbar , options ) {
2016-08-31 12:06:17 +02:00
var converse = this . _ _super _ _ . converse ;
2016-02-13 23:58:50 +01:00
if ( ! converse . show _toolbar ) {
return ;
}
var data = this . model . toJSON ( ) ;
options = _ . extend ( options || { } , {
FINISHED : FINISHED ,
UNENCRYPTED : UNENCRYPTED ,
UNVERIFIED : UNVERIFIED ,
VERIFIED : VERIFIED ,
2016-02-14 12:23:32 +01:00
// FIXME: Leaky abstraction MUC
2016-02-13 23:58:50 +01:00
allow _otr : converse . allow _otr && ! this . is _chatroom ,
label _end _encrypted _conversation : _ _ ( 'End encrypted conversation' ) ,
label _refresh _encrypted _conversation : _ _ ( 'Refresh encrypted conversation' ) ,
label _start _encrypted _conversation : _ _ ( 'Start encrypted conversation' ) ,
label _verify _with _fingerprints : _ _ ( 'Verify with fingerprints' ) ,
label _verify _with _smp : _ _ ( 'Verify with SMP' ) ,
label _whats _this : _ _ ( "What\'s this?" ) ,
otr _status _class : OTR _CLASS _MAPPING [ data . otr _status ] ,
otr _tooltip : this . getOTRTooltip ( ) ,
otr _translated _status : OTR _TRANSLATED _MAPPING [ data . otr _status ] ,
} ) ;
2016-10-27 13:30:58 +02:00
this . _ _super _ _ . renderToolbar . apply ( this , arguments ) ;
2016-02-14 12:23:32 +01:00
this . $el . find ( '.chat-toolbar' ) . append (
converse . templates . toolbar _otr (
_ . extend ( this . model . toJSON ( ) , options || { } )
) ) ;
2016-02-13 23:58:50 +01:00
return this ;
}
}
} ,
initialize : function ( ) {
/ * T h e i n i t i a l i z e f u n c t i o n g e t s c a l l e d a s s o o n a s t h e p l u g i n i s
* loaded by converse . js ' s plugin machinery .
* /
var converse = this . converse ;
2016-02-28 09:30:07 +01:00
// Translation aware constants
// ---------------------------
// We can only call the __ translation method *after* converse.js
// has been initialized and with it the i18n machinery. That's why
// we do it here in the "initialize" method and not at the top of
// the module.
OTR _TRANSLATED _MAPPING [ UNENCRYPTED ] = _ _ ( 'unencrypted' ) ;
OTR _TRANSLATED _MAPPING [ UNVERIFIED ] = _ _ ( 'unverified' ) ;
OTR _TRANSLATED _MAPPING [ VERIFIED ] = _ _ ( 'verified' ) ;
OTR _TRANSLATED _MAPPING [ FINISHED ] = _ _ ( 'finished' ) ;
2016-02-19 11:43:46 +01:00
// For translations
_ _ = utils . _ _ . bind ( converse ) ;
2016-02-13 23:58:50 +01:00
// Configuration values for this plugin
var settings = {
allow _otr : true ,
cache _otr _key : false ,
use _otr _by _default : false
} ;
2016-03-01 09:57:57 +01:00
_ . extend ( converse . default _settings , settings ) ;
2016-02-13 23:58:50 +01:00
_ . extend ( converse , settings ) ;
_ . extend ( converse , _ . pick ( converse . user _settings , Object . 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 ( typeof pass === 'undefined' ) {
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 ( typeof pass !== "undefined" ) {
// 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 ;
}
} ) ;
}
} ) ;
} ) ) ;