@ -35,12 +35,10 @@ weechat.factory('connection',
$log . debug ( 'Connecting to URL: ' , url ) ;
$log . debug ( 'Connecting to URL: ' , url ) ;
var weechatIs Pre2 _9 = false ;
var weechatAssumed Pre2 _9 = false ;
var onopen = function ( ) {
var onopen = function ( ) {
var _performHandshake = function ( ) {
var _performHandshake = function ( ) {
return new Promise ( function ( resolve ) {
return new Promise ( function ( resolve ) {
// First a handshake is sent to determine authentication method
// First a handshake is sent to determine authentication method
// This is only supported for weechat >= 2.9
// This is only supported for weechat >= 2.9
// If after 'a while' weechat does not respond
// If after 'a while' weechat does not respond
@ -54,7 +52,7 @@ weechat.factory('connection',
// Wait long enough to assume we are on a version < 2.9
// Wait long enough to assume we are on a version < 2.9
var handShakeTimeout = setTimeout ( function ( ) {
var handShakeTimeout = setTimeout ( function ( ) {
weechatIs Pre2 _9 = true ;
weechatAssumed Pre2 _9 = true ;
console . log ( 'Weechat\'s version is assumed to be < 2.9' ) ;
console . log ( 'Weechat\'s version is assumed to be < 2.9' ) ;
resolve ( ) ;
resolve ( ) ;
} , WAIT _TIME _OLD _WEECHAT ) ;
} , WAIT _TIME _OLD _WEECHAT ) ;
@ -68,43 +66,35 @@ weechat.factory('connection',
clearTimeout ( handShakeTimeout ) ;
clearTimeout ( handShakeTimeout ) ;
resolve ( message ) ;
resolve ( message ) ;
} ) ;
} ) ;
} ) ;
} ) ;
} ;
}
var _askTotp = function ( useTotp ) {
var _askTotp = function ( useTotp ) {
return new Promise ( function ( resolve ) {
return new Promise ( function ( resolve ) {
// If weechat is < 2.9 the totp will be a setting (checkbox)
// If weechat is < 2.9 the totp will be a setting (checkbox)
// Otherwise the handshake will specify it
// Otherwise the handshake will specify it
if ( useTotp ) {
if ( useTotp ) {
// Ask the user to input his TOTP
// Ask the user to input his TOTP
var totp = prompt ( "Please enter your TOTP Token" ) ;
var totp = prompt ( "Please enter your TOTP Token" ) ;
resolve ( totp ) ;
resolve ( totp ) ;
} else {
} else {
// User does not use TOTP, don't ask
// User does not use TOTP, don't ask
resolve ( null ) ;
resolve ( null ) ;
}
}
} ) ;
} )
} ;
}
// Helper methods for initialization commands
// Helper methods for initialization commands
// This method is used to initialize weechat < 2.9
// This method is used to initialize weechat < 2.9
var _initializeConnectionPre29 = function ( passwd , totp ) {
var _initializeConnectionPre29 = function ( passwd , totp ) {
// This is not secure, this has to be specifically allowed with a setting
// This is not secure, this has to be specifically allowed with a setting
// Otherwise an attacker could persuade the client to send it's password
// Otherwise an attacker could persuade the client to send it's password
// Or due to latency the client could think weechat was an older version
// Or due to latency the client could think weechat was an older version
if ( ! settings . compatibilityWeechat28 )
if ( ! settings . compatibilityWeechat28 ) {
{
$rootScope . oldWeechatError = true ;
$rootScope . oldWeechatError = true ;
$rootScope . $emit ( 'relayDisconnect' ) ;
$rootScope . $emit ( 'relayDisconnect' ) ;
$rootScope . $digest ( ) // Have to do this otherwise change detection doesn't see the error.
$rootScope . $digest ( ) ; // Have to do this otherwise change detection doesn't see the error.
throw new Error ( 'Plaintt ext authentication not allowed.' ) ;
throw new Error ( 'Plaintext authentication not allowed.' ) ;
}
}
// Escape comma in password (#937)
// Escape comma in password (#937)
@ -120,8 +110,8 @@ weechat.factory('connection',
// Wait a little bit until the init is sent
// Wait a little bit until the init is sent
return new Promise ( function ( resolve ) {
return new Promise ( function ( resolve ) {
setTimeout ( ( ) => resolve ( ) , 5 ) ;
setTimeout ( function ( ) { resolve ( ) ; } , 5 ) ;
} )
} ) ;
} ;
} ;
@ -129,48 +119,39 @@ weechat.factory('connection',
// This method is used to initialize weechat >= 2.9
// This method is used to initialize weechat >= 2.9
var salt ;
var salt ;
var _initializeConnection29 = function ( passwd , nonce , iterations , totp ) {
var _initializeConnection29 = function ( passwd , nonce , iterations , totp ) {
return window . crypto . subtle . importKey (
return window . crypto . subtle . importKey (
'raw' ,
'raw' ,
utils . stringToUTF8Array ( passwd ) ,
utils . stringToUTF8Array ( passwd ) ,
{ name : 'PBKDF2' } , //{name: 'HMAC', hash: 'SHA-512'},
{ name : 'PBKDF2' } , //{name: 'HMAC', hash: 'SHA-512'},
false ,
false ,
[ 'deriveBits' ]
[ 'deriveBits' ]
) . then ( function ( key ) {
) . then ( function ( key ) {
var clientnonce = window . crypto . getRandomValues ( new Uint8Array ( 16 ) ) ;
//nonce:clientnonce, 3A is a ':' in ASCII
salt = utils . concatenateTypedArray ( utils . concatenateTypedArray ( nonce , new Uint8Array ( [ 0x3A ] ) ) , window . crypto . getRandomValues ( new Uint8Array ( 16 ) ) ) ; //nonce:cnonce, 3A is a ':' in ASCII
salt = utils . concatenateTypedArrays (
nonce , new Uint8Array ( [ 0x3A ] ) , clientnonce ) ;
return window . crypto . subtle . deriveBits (
return window . crypto . subtle . deriveBits (
{
{
name : 'PBKDF2' ,
name : 'PBKDF2' ,
hash : 'SHA-512' ,
hash : 'SHA-512' ,
salt : salt ,
salt : salt ,
iterations : iterations ,
iterations : iterations ,
} ,
} , key , 512
key , //your key from generateKey or importKey
512
) ;
) ;
} ) . then ( function ( hash ) {
} ) . then ( function ( hash ) {
ngWebsockets . send (
ngWebsockets . send (
weeChat . Protocol . formatInit29 (
weeChat . Protocol . formatInit29 (
'pbkdf2+sha512:' + utils . bytetoHexString ( salt ) + ':' + iterations + ':' + utils . bytetoHexString ( hash ) ,
'pbkdf2+sha512:' + utils . bytetoHexString ( salt ) + ':' +
iterations + ':' + utils . bytetoHexString ( hash ) ,
totp
totp
)
)
) ;
) ;
// Wait a little bit until the init is sent
// Wait a little bit until the init is sent
return new Promise ( function ( resolve ) {
return new Promise ( function ( resolve ) {
setTimeout ( function ( ) { resolve ( ) ; } , 5 ) ;
setTimeout ( ( ) => resolve ( ) , 5 ) ;
} ) ;
} )
} ) ;
} ) ;
} ;
} ;
var _requestHotlist = function ( ) {
var _requestHotlist = function ( ) {
@ -295,61 +276,49 @@ weechat.factory('connection',
$rootScope . angularTimeFormat = angularFormat ;
$rootScope . angularTimeFormat = angularFormat ;
} ;
} ;
var passwordMethod
var passwordMethod ;
var totpRequested ;
var totpRequested ;
var nonce ;
var nonce ;
var iterations ;
var iterations ;
_performHandshake ( ) . then (
_performHandshake ( ) . then (
// Wait for weechat to respond or handshake times out
//Wait for weechat to respond or handshake times out
function ( message ) {
function ( message )
{
// Do nothing if the handshake was received
// Do nothing if the handshake was received
// after concluding weechat was an old version
// after concluding weechat was an old version
// TODO maybe warn the user here
// TODO maybe warn the user here
if ( weechatIs Pre2_9 ) {
if ( weechatAssumed Pre2 _9 ) {
return ;
return ;
}
}
passwordMethod = message . objects [ 0 ] . content . password _hash _algo ;
var content = message . objects [ 0 ] . content ;
totpRequested = message . objects [ 0 ] . content . totp === 'on' ? true : false ;
passwordMethod = content . password _hash _algo ;
nonce = utils . hexStringToByte ( message . objects [ 0 ] . content . nonce ) ;
totpRequested = ( content . totp === 'on' ) ;
iterations = message . objects [ 0 ] . content . password _hash _iterations ;
nonce = utils . hexStringToByte ( content . nonce ) ;
iterations = content . password _hash _iterations ;
if ( passwordMethod != "pbkdf2+sha512" )
if ( passwordMethod != "pbkdf2+sha512" ) {
{
$rootScope . hashAlgorithmDisagree = true ;
$rootScope . hashAlgorithmDisagree = true ;
$rootScope . $emit ( 'relayDisconnect' ) ;
$rootScope . $emit ( 'relayDisconnect' ) ;
$rootScope . $digest ( ) // Have to do this otherwise change detection doesn't see the error.
$rootScope . $digest ( ) ; // Have to do this otherwise change detection doesn't see the error.
throw new Error ( 'No password hash algorithm returned.' ) ;
throw new Error ( 'No supported password hash algorithm returned.' ) ;
}
}
}
}
) . then ( function ( ) {
) . then ( function ( ) {
if ( weechatAssumedPre2 _9 ) {
if ( weechatIsPre2 _9 )
{
// Ask the user for the TOTP token if this is enabled
// Ask the user for the TOTP token if this is enabled
return _askTotp ( useTotp )
return _askTotp ( useTotp )
. then ( function ( totp ) {
. then ( function ( totp ) {
return _initializeConnectionPre29 ( passwd , totp )
return _initializeConnectionPre29 ( passwd , totp ) ;
} )
} ) ;
} else {
} else {
// Weechat version >= 2.9
// Weechat version >= 2.9
return _askTotp ( totpRequested )
return _askTotp ( totpRequested )
. then ( function ( totp ) {
. then ( function ( totp ) {
return _initializeConnection29 ( passwd , nonce , iterations , totp )
return _initializeConnection29 ( passwd , nonce , iterations , totp ) ;
} )
} ) ;
}
}
} ) . then ( function ( ) {
} ) . then ( function ( ) {
// The Init was sent, weechat will not respond
// The Init was sent, weechat will not respond
// Wait until either the connection closes
// Wait until either the connection closes
// Or try to send version and see if weechat responds
// Or try to send version and see if weechat responds
@ -358,9 +327,7 @@ weechat.factory('connection',
name : 'version'
name : 'version'
} )
} )
) ;
) ;
} ) . then ( function ( version ) {
} ) . then ( function ( version ) {
// From now on we are assumed initialized
// From now on we are assumed initialized
// We don't know for sure because weechat does not respond
// We don't know for sure because weechat does not respond
// All we know is the socket wasn't closed afer waiting a little bit
// All we know is the socket wasn't closed afer waiting a little bit
@ -417,10 +384,6 @@ weechat.factory('connection',
} ) ;
} ) ;
} ;
} ;
var onmessage = function ( ) {
} ;
var onclose = function ( evt ) {
var onclose = function ( evt ) {
/ *
/ *
* Handles websocket disconnection
* Handles websocket disconnection
@ -450,7 +413,9 @@ weechat.factory('connection',
var handleWrongPassword = function ( ) {
var handleWrongPassword = function ( ) {
// Connection got closed, lets check if we ever was connected successfully
// Connection got closed, lets check if we ever was connected successfully
if ( ! $rootScope . waseverconnected && ! $rootScope . errorMessage && ! $rootScope . oldWeechatError && ! $rootScope . hashAlgorithmDisagree ) {
if ( ! $rootScope . waseverconnected && ! $rootScope . errorMessage &&
! $rootScope . oldWeechatError && ! $rootScope . hashAlgorithmDisagree )
{
$rootScope . passwordError = true ;
$rootScope . passwordError = true ;
$rootScope . $apply ( ) ;
$rootScope . $apply ( ) ;
}
}
@ -485,7 +450,6 @@ weechat.factory('connection',
'binaryType' : "arraybuffer" ,
'binaryType' : "arraybuffer" ,
'onopen' : onopen ,
'onopen' : onopen ,
'onclose' : onclose ,
'onclose' : onclose ,
'onmessage' : onmessage ,
'onerror' : onerror
'onerror' : onerror
} ) ;
} ) ;
} catch ( e ) {
} catch ( e ) {