2012-04-17 19:13:18 -04:00
//
// Copyright 2012 "Leberwurscht" <leberwurscht@hoegners.de>
//
// This file is dual-licensed under the MIT license (see MIT.txt) and the AGPL license (see jappix/COPYING).
//
2012-04-13 11:05:16 -04:00
function jappixmini _addon _xor ( str1 , str2 ) {
if ( str1 . length != str2 . length ) throw "not same length" ;
2012-04-17 16:32:54 -04:00
var encoded = "" ;
2012-04-13 11:05:16 -04:00
2012-04-17 16:32:54 -04:00
for ( var i = 0 ; i < str1 . length ; i ++ ) {
2012-04-13 11:05:16 -04:00
var a = str1 . charCodeAt ( i ) ;
var b = str2 . charCodeAt ( i ) ;
var c = a ^ b ;
encoded += String . fromCharCode ( c ) ;
}
return encoded ;
}
function jappixmini _addon _set _client _secret ( password ) {
2012-04-14 12:23:42 -04:00
if ( ! password ) return ;
2012-04-17 16:32:54 -04:00
var salt1 = "h8doCRekWto0njyQohKpdx6BN0UTyC6N" ;
var salt2 = "jdX8OwFC1kWAq3s9uOyAcE8g3UNNO5t3" ;
2012-04-14 12:23:42 -04:00
2012-04-17 16:32:54 -04:00
var client _secret1 = str _sha1 ( salt1 + password ) ;
var client _secret2 = str _sha1 ( salt2 + password ) ;
var client _secret = client _secret1 + client _secret2 ;
2012-04-14 12:23:42 -04:00
2012-04-15 17:19:37 -04:00
setPersistent ( 'jappix-mini' , 'client-secret' , client _secret ) ;
2012-04-14 12:23:42 -04:00
console . log ( "client secret set" ) ;
2012-04-13 11:05:16 -04:00
}
2012-04-15 16:57:25 -04:00
function jappixmini _addon _get _client _secret ( callback ) {
2012-04-17 16:32:54 -04:00
var client _secret = getPersistent ( 'jappix-mini' , 'client-secret' ) ;
2012-04-13 11:05:16 -04:00
if ( client _secret === null ) {
2012-04-17 16:32:54 -04:00
var div = document . getElementById ( "#jappixmini-password-query-div" ) ;
2012-04-15 16:57:25 -04:00
if ( ! div ) {
2013-06-22 18:26:49 -04:00
div = $ ( '<div id="jappixmini-password-query-div" style="position:fixed;padding:1em;background-color:#F00;color:#fff;top:50px;left:650px;">Retype your Friendica password for chatting:<br></div>' ) ;
2012-04-15 16:57:25 -04:00
2012-04-17 16:32:54 -04:00
var input = $ ( '<input type="password" id="jappixmini-password-query-input">' )
2012-04-15 16:57:25 -04:00
div . append ( input ) ;
2012-04-17 16:32:54 -04:00
var button = $ ( '<input type="button" value="OK" id="jappixmini-password-query-button">' ) ;
2012-04-15 16:57:25 -04:00
div . append ( button ) ;
$ ( "body" ) . append ( div ) ;
}
2012-04-13 11:05:16 -04:00
button . click ( function ( ) {
2012-04-17 16:32:54 -04:00
var password = $ ( "#jappixmini-password-query-input" ) . val ( ) ;
2012-04-13 11:05:16 -04:00
jappixmini _addon _set _client _secret ( password ) ;
div . remove ( ) ;
2012-04-15 16:57:25 -04:00
2012-04-17 16:32:54 -04:00
var client _secret = getPersistent ( 'jappix-mini' , 'client-secret' ) ;
2012-04-15 16:57:25 -04:00
callback ( client _secret ) ;
2012-04-13 11:05:16 -04:00
} ) ;
}
2012-04-15 16:57:25 -04:00
else {
callback ( client _secret ) ;
}
2012-04-13 11:05:16 -04:00
}
2012-04-15 16:57:25 -04:00
function jappixmini _addon _encrypt _password ( password , callback ) {
jappixmini _addon _get _client _secret ( function ( client _secret ) {
// add \0 to password until it has the same length as secret
if ( password . length > client _secret . length - 1 ) throw "password too long" ;
while ( password . length < client _secret . length ) {
password += "\0" ;
}
2012-04-13 11:05:16 -04:00
2012-04-15 16:57:25 -04:00
// xor password with secret
2012-04-17 16:32:54 -04:00
var encrypted _password = jappixmini _addon _xor ( client _secret , password ) ;
2012-04-13 11:05:16 -04:00
2012-04-15 16:57:25 -04:00
encrypted _password = encodeURI ( encrypted _password )
callback ( encrypted _password ) ;
} ) ;
2012-04-13 11:05:16 -04:00
}
2012-04-15 16:57:25 -04:00
function jappixmini _addon _decrypt _password ( encrypted _password , callback ) {
2012-04-13 11:05:16 -04:00
encrypted _password = decodeURI ( encrypted _password ) ;
2012-04-15 16:57:25 -04:00
jappixmini _addon _get _client _secret ( function ( client _secret ) {
// xor password with secret
2012-04-17 16:32:54 -04:00
var password = jappixmini _addon _xor ( client _secret , encrypted _password ) ;
2012-04-13 11:05:16 -04:00
2012-04-15 16:57:25 -04:00
// remove \0
2012-04-17 16:32:54 -04:00
var first _null = password . indexOf ( "\0" )
2012-04-16 17:39:21 -04:00
if ( first _null == - 1 ) throw "Decrypted password does not contain \\0" ;
2012-04-15 16:57:25 -04:00
password = password . substr ( 0 , first _null ) ;
2012-04-13 11:05:16 -04:00
2012-04-15 16:57:25 -04:00
callback ( password ) ;
} ) ;
2012-04-13 11:05:16 -04:00
}
2012-04-17 15:18:11 -04:00
function jappixmini _manage _roster ( contacts , contacts _hash , autoapprove , autosubscribe ) {
2012-04-13 11:05:16 -04:00
// listen for subscriptions
con . registerHandler ( 'presence' , function ( presence ) {
var type = presence . getType ( ) ;
if ( type != "subscribe" ) return ;
var from = fullXID ( getStanzaFrom ( presence ) ) ;
var xid = bareXID ( from ) ;
2012-04-16 17:40:40 -04:00
var pstatus = presence . getStatus ( ) ;
2012-04-13 11:05:16 -04:00
2012-04-17 16:32:54 -04:00
var approve ;
2012-04-16 17:40:40 -04:00
if ( autoapprove && contacts [ xid ] !== undefined ) {
// approve known address
approve = true ;
console . log ( "Approve known Friendica contact " + xid + "." ) ;
}
else if ( autoapprove && pstatus && pstatus . indexOf ( "Friendica" ) != - 1 ) {
// Unknown address claims to be a Friendica contact.
// This is probably because the other side knows our
// address, but we do not know the other side yet.
// But it's only a matter of time, so wait - do not
// approve yet and do not annoy the user by asking.
approve = false ;
console . log ( "Do not approve unknown Friendica contact " + xid + " - wait instead." ) ;
}
else {
// In all other cases, ask the user.
2012-04-17 16:32:54 -04:00
var message = "Accept " + xid + " for chat?" ;
2012-04-16 17:40:40 -04:00
if ( pstatus ) message += "\n\nStatus:\n" + pstatus ;
approve = confirm ( message ) ;
2012-04-17 15:00:03 -04:00
// do not ask any more
if ( ! approve ) sendSubscribe ( xid , "unsubscribed" ) ;
2012-04-16 17:40:40 -04:00
}
2012-04-13 11:05:16 -04:00
if ( approve ) {
2012-04-17 16:32:54 -04:00
var name = contacts [ xid ] ;
2012-04-17 15:14:28 -04:00
if ( ! name ) name = xid ;
2012-04-17 16:32:54 -04:00
acceptSubscribe ( xid , name ) ;
2012-04-17 16:45:18 -04:00
console . log ( "Accepted " + xid + " (" + name + ") for chat." ) ;
2012-04-13 11:05:16 -04:00
}
} ) ;
// autosubscribe
2012-04-15 19:04:45 -04:00
if ( ! autosubscribe ) return ;
2012-04-17 16:32:54 -04:00
var stored _hash = getPersistent ( "jappix-mini" , "contacts-hash" ) ;
var contacts _changed = ( stored _hash != contacts _hash ) ; // stored_hash gets updated later if everything was successful
2012-04-17 15:18:11 -04:00
if ( ! contacts _changed ) return ;
2012-04-17 15:15:32 -04:00
console . log ( "Start autosubscribe." ) ;
2012-04-15 19:04:45 -04:00
var get _roster = new JSJaCIQ ( ) ;
get _roster . setType ( 'get' ) ;
get _roster . setQuery ( NS _ROSTER ) ;
con . send ( get _roster , function ( iq ) {
var handleXML = iq . getQuery ( ) ;
// filter out contacts that are already in the roster
$ ( handleXML ) . find ( 'item' ) . each ( function ( ) {
2012-04-17 16:32:54 -04:00
var node = $ ( this ) ;
var xid = node . attr ( "jid" ) ;
var name = node . attr ( "name" ) ;
var subscription = node . attr ( "subscription" ) ;
2012-04-15 19:04:45 -04:00
2012-04-17 16:32:54 -04:00
// ignore accounts that are not in the list
2012-04-15 19:04:45 -04:00
if ( contacts [ xid ] === undefined ) return ;
2012-04-17 17:09:26 -04:00
// add to Friendica group or change name if necessary
2012-04-17 16:32:54 -04:00
var groups = [ ] ;
2012-04-17 17:38:27 -04:00
var group _missing = false ;
2012-04-17 16:32:54 -04:00
node . find ( 'group' ) . each ( function ( ) {
2012-04-16 18:41:22 -04:00
var group _text = $ ( this ) . text ( ) ;
2012-04-17 16:32:54 -04:00
if ( group _text ) groups . push ( group _text ) ;
2012-04-16 18:41:22 -04:00
} ) ;
2012-04-17 17:38:27 -04:00
if ( $ . inArray ( "Friendica" , groups ) == - 1 ) {
group _missing = true ;
2012-04-16 18:41:22 -04:00
groups . push ( "Friendica" ) ;
2012-04-17 17:38:27 -04:00
}
if ( group _missing || name != contacts [ xid ] ) {
2012-04-17 17:09:26 -04:00
sendRoster ( xid , null , contacts [ xid ] , groups ) ;
console . log ( "Added " + xid + " to Friendica group and set name to " + contacts [ xid ] + "." ) ;
2012-04-16 18:41:22 -04:00
}
// authorize if necessary
if ( subscription == "to" ) {
sendSubscribe ( xid , 'subscribed' ) ;
2012-04-17 15:15:32 -04:00
console . log ( "Authorized " + xid + " automatically." ) ;
2012-04-16 18:41:22 -04:00
}
2012-04-15 19:04:45 -04:00
// remove from list
delete contacts [ xid ] ;
} ) ;
// go through remaining contacts
for ( var xid in contacts ) { if ( ! contacts . hasOwnProperty ( xid ) ) continue ;
// subscribe
var presence = new JSJaCPresence ( ) ;
presence . setTo ( xid ) ;
presence . setType ( "subscribe" ) ;
2012-04-16 17:40:40 -04:00
// must contain the word "~Friendica" so the other side knows
// how to handle this
presence . setStatus ( "I'm " + MINI _NICKNAME + " from ~Friendica.\n[machine-generated message]" ) ;
2012-04-15 19:04:45 -04:00
con . send ( presence ) ;
2012-04-17 15:15:32 -04:00
console . log ( "Subscribed to " + xid + " automatically." ) ;
2012-04-15 19:04:45 -04:00
// add to roster
var iq = new JSJaCIQ ( ) ;
iq . setType ( 'set' ) ;
var iqQuery = iq . setQuery ( NS _ROSTER ) ;
var item = iqQuery . appendChild ( iq . buildNode ( 'item' , { 'xmlns' : NS _ROSTER , 'jid' : xid } ) ) ;
item . setAttribute ( 'name' , contacts [ xid ] ) ;
item . appendChild ( iq . buildNode ( 'group' , { 'xmlns' : NS _ROSTER } , "Friendica" ) ) ;
con . send ( iq ) ;
2012-04-17 16:45:18 -04:00
console . log ( "Added " + xid + " (" + contacts [ xid ] + ") to roster." ) ;
2012-04-13 11:05:16 -04:00
}
2012-04-17 15:18:11 -04:00
setPersistent ( "jappix-mini" , "contacts-hash" , contacts _hash ) ;
2012-04-17 15:15:32 -04:00
console . log ( "Autosubscribe done." ) ;
2012-04-15 19:04:45 -04:00
} ) ;
2012-04-17 15:15:32 -04:00
2012-04-13 11:05:16 -04:00
}
2012-04-15 06:20:53 -04:00
function jappixmini _addon _subscribe ( ) {
if ( ! window . con ) {
alert ( "Not connected." ) ;
return ;
}
2012-04-17 16:32:54 -04:00
var xid = prompt ( "Jabber address" ) ;
2012-04-15 06:20:53 -04:00
sendSubscribe ( xid , "subscribe" ) ;
}
2013-09-27 17:33:35 -04:00
function jappixmini _addon _start ( server , username , proxy , bosh , encrypted , password , nickname , contacts , contacts _hash , autoapprove , autosubscribe , groupchats ) {
2012-04-17 16:32:54 -04:00
var handler = function ( password ) {
2012-04-15 16:57:25 -04:00
// check if settings have changed, reinitialize jappix mini if this is the case
2012-04-17 16:32:54 -04:00
var settings _identifier = str _sha1 ( server ) ;
2012-04-15 16:57:25 -04:00
settings _identifier += str _sha1 ( username ) ;
2012-04-16 17:39:46 -04:00
settings _identifier += str _sha1 ( proxy ) ;
2012-04-15 16:57:25 -04:00
settings _identifier += str _sha1 ( bosh ) ;
settings _identifier += str _sha1 ( password ) ;
settings _identifier += str _sha1 ( nickname ) ;
2012-04-17 16:32:54 -04:00
var saved _identifier = getDB ( "jappix-mini" , "settings-identifier" ) ;
2012-04-17 15:18:11 -04:00
if ( saved _identifier != settings _identifier ) {
disconnectMini ( ) ;
removeDB ( 'jappix-mini' , 'dom' ) ;
removePersistent ( "jappix-mini" , "contacts-hash" ) ;
}
setDB ( "jappix-mini" , "settings-identifier" , settings _identifier ) ;
2012-04-15 16:57:25 -04:00
2012-04-17 16:32:54 -04:00
// set HOST_BOSH
if ( proxy )
HOST _BOSH = proxy + "?host_bosh=" + encodeURI ( bosh ) ;
else
HOST _BOSH = bosh ;
2012-04-15 16:57:25 -04:00
// start jappix mini
2013-09-27 17:33:35 -04:00
MINI _GROUPCHATS = groupchats ;
2012-04-15 16:57:25 -04:00
MINI _NICKNAME = nickname ;
2012-04-16 15:16:24 -04:00
LOCK _HOST = "off" ;
2012-04-15 16:57:25 -04:00
launchMini ( true , false , server , username , password ) ;
2012-04-16 17:38:00 -04:00
2012-04-17 15:13:31 -04:00
// increase priority over other Jabber clients - does not seem to work?
2012-04-17 16:32:54 -04:00
var priority = 101 ;
2012-04-17 15:13:31 -04:00
presenceMini ( null , null , priority ) ;
2012-04-16 17:38:00 -04:00
2012-04-17 15:18:11 -04:00
jappixmini _manage _roster ( contacts , contacts _hash , autoapprove , autosubscribe )
2012-04-15 16:57:25 -04:00
}
// decrypt password if necessary
2012-04-15 06:20:53 -04:00
if ( encrypted )
2012-04-15 16:57:25 -04:00
jappixmini _addon _decrypt _password ( password , handler ) ;
else
handler ( password ) ;
2012-04-13 11:05:16 -04:00
}