friendica-addons/jappixmini/lib.js

282 lines
8.6 KiB
JavaScript
Raw Normal View History

//
// 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 17:05:16 +02:00
function jappixmini_addon_xor(str1, str2) {
if (str1.length != str2.length) throw "not same length";
2012-04-17 22:32:54 +02:00
var encoded = "";
2012-04-13 17:05:16 +02:00
2012-04-17 22:32:54 +02:00
for (var i=0; i<str1.length;i++) {
2012-04-13 17:05:16 +02: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 18:23:42 +02:00
if (!password) return;
2012-04-17 22:32:54 +02:00
var salt1 = "h8doCRekWto0njyQohKpdx6BN0UTyC6N";
var salt2 = "jdX8OwFC1kWAq3s9uOyAcE8g3UNNO5t3";
2012-04-14 18:23:42 +02:00
2012-04-17 22:32:54 +02: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 18:23:42 +02:00
setPersistent('jappix-mini', 'client-secret', client_secret);
2012-04-14 18:23:42 +02:00
console.log("client secret set");
2012-04-13 17:05:16 +02:00
}
function jappixmini_addon_get_client_secret(callback) {
2012-04-17 22:32:54 +02:00
var client_secret = getPersistent('jappix-mini', 'client-secret');
2012-04-13 17:05:16 +02:00
if (client_secret===null) {
2012-04-17 22:32:54 +02:00
var div = document.getElementById("#jappixmini-password-query-div");
if (!div) {
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-17 22:32:54 +02:00
var input = $('<input type="password" id="jappixmini-password-query-input">')
div.append(input);
2012-04-17 22:32:54 +02:00
var button = $('<input type="button" value="OK" id="jappixmini-password-query-button">');
div.append(button);
$("body").append(div);
}
2012-04-13 17:05:16 +02:00
button.click(function(){
2012-04-17 22:32:54 +02:00
var password = $("#jappixmini-password-query-input").val();
2012-04-13 17:05:16 +02:00
jappixmini_addon_set_client_secret(password);
div.remove();
2012-04-17 22:32:54 +02:00
var client_secret = getPersistent('jappix-mini', 'client-secret');
callback(client_secret);
2012-04-13 17:05:16 +02:00
});
}
else {
callback(client_secret);
}
2012-04-13 17:05:16 +02: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 17:05:16 +02:00
// xor password with secret
2012-04-17 22:32:54 +02:00
var encrypted_password = jappixmini_addon_xor(client_secret, password);
2012-04-13 17:05:16 +02:00
encrypted_password = encodeURI(encrypted_password)
callback(encrypted_password);
});
2012-04-13 17:05:16 +02:00
}
function jappixmini_addon_decrypt_password(encrypted_password, callback) {
2012-04-13 17:05:16 +02:00
encrypted_password = decodeURI(encrypted_password);
jappixmini_addon_get_client_secret(function(client_secret){
// xor password with secret
2012-04-17 22:32:54 +02:00
var password = jappixmini_addon_xor(client_secret, encrypted_password);
2012-04-13 17:05:16 +02:00
// remove \0
2012-04-17 22:32:54 +02:00
var first_null = password.indexOf("\0")
if (first_null==-1) throw "Decrypted password does not contain \\0";
password = password.substr(0, first_null);
2012-04-13 17:05:16 +02:00
callback(password);
});
2012-04-13 17:05:16 +02:00
}
function jappixmini_manage_roster(contacts, contacts_hash, autoapprove, autosubscribe) {
2012-04-13 17:05:16 +02: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);
var pstatus = presence.getStatus();
2012-04-13 17:05:16 +02:00
2012-04-17 22:32:54 +02:00
var approve;
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 22:32:54 +02:00
var message = "Accept "+xid+" for chat?";
if (pstatus) message += "\n\nStatus:\n"+pstatus;
approve = confirm(message);
// do not ask any more
if (!approve) sendSubscribe(xid, "unsubscribed");
}
2012-04-13 17:05:16 +02:00
if (approve) {
2012-04-17 22:32:54 +02:00
var name = contacts[xid];
if (!name) name = xid;
2012-04-17 22:32:54 +02:00
acceptSubscribe(xid, name);
2012-04-17 22:45:18 +02:00
console.log("Accepted "+xid+" ("+name+") for chat.");
2012-04-13 17:05:16 +02:00
}
});
// autosubscribe
2012-04-16 01:04:45 +02:00
if (!autosubscribe) return;
2012-04-17 22:32:54 +02: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
if (!contacts_changed) return;
2012-04-17 21:15:32 +02:00
console.log("Start autosubscribe.");
2012-04-16 01:04:45 +02: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 22:32:54 +02:00
var node = $(this);
var xid = node.attr("jid");
var name = node.attr("name");
var subscription = node.attr("subscription");
2012-04-16 01:04:45 +02:00
2012-04-17 22:32:54 +02:00
// ignore accounts that are not in the list
2012-04-16 01:04:45 +02:00
if (contacts[xid]===undefined) return;
2012-04-17 23:09:26 +02:00
// add to Friendica group or change name if necessary
2012-04-17 22:32:54 +02:00
var groups = [];
var group_missing = false;
2012-04-17 22:32:54 +02:00
node.find('group').each(function() {
var group_text = $(this).text();
2012-04-17 22:32:54 +02:00
if (group_text) groups.push(group_text);
});
if ($.inArray("Friendica", groups)==-1) {
group_missing = true;
groups.push("Friendica");
}
if (group_missing || name!=contacts[xid]) {
2012-04-17 23:09:26 +02:00
sendRoster(xid, null, contacts[xid], groups);
console.log("Added "+xid+" to Friendica group and set name to "+contacts[xid]+".");
}
// authorize if necessary
if (subscription=="to") {
sendSubscribe(xid, 'subscribed');
2012-04-17 21:15:32 +02:00
console.log("Authorized "+xid+" automatically.");
}
2012-04-16 01:04:45 +02: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");
// 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-16 01:04:45 +02:00
con.send(presence);
2012-04-17 21:15:32 +02:00
console.log("Subscribed to "+xid+" automatically.");
2012-04-16 01:04:45 +02: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 22:45:18 +02:00
console.log("Added "+xid+" ("+contacts[xid]+") to roster.");
2012-04-13 17:05:16 +02:00
}
setPersistent("jappix-mini", "contacts-hash", contacts_hash);
2012-04-17 21:15:32 +02:00
console.log("Autosubscribe done.");
2012-04-16 01:04:45 +02:00
});
2012-04-17 21:15:32 +02:00
2012-04-13 17:05:16 +02:00
}
function jappixmini_addon_subscribe() {
if (!window.con) {
alert("Not connected.");
return;
}
2012-04-17 22:32:54 +02:00
var xid = prompt("Jabber address");
sendSubscribe(xid, "subscribe");
}
function jappixmini_addon_start(server, username, proxy, bosh, encrypted, password, nickname, contacts, contacts_hash, autoapprove, autosubscribe, groupchats) {
2012-04-17 22:32:54 +02:00
var handler = function(password){
// check if settings have changed, reinitialize jappix mini if this is the case
2012-04-17 22:32:54 +02:00
var settings_identifier = str_sha1(server);
settings_identifier += str_sha1(username);
settings_identifier += str_sha1(proxy);
settings_identifier += str_sha1(bosh);
settings_identifier += str_sha1(password);
settings_identifier += str_sha1(nickname);
2012-04-17 22:32:54 +02:00
var saved_identifier = getDB("jappix-mini", "settings-identifier");
if (saved_identifier != settings_identifier) {
disconnectMini();
removeDB('jappix-mini', 'dom');
removePersistent("jappix-mini", "contacts-hash");
}
setDB("jappix-mini", "settings-identifier", settings_identifier);
2012-04-17 22:32:54 +02:00
// set HOST_BOSH
if (proxy)
HOST_BOSH = proxy+"?host_bosh="+encodeURI(bosh);
else
HOST_BOSH = bosh;
// start jappix mini
MINI_GROUPCHATS = groupchats;
MINI_NICKNAME = nickname;
2012-04-16 21:16:24 +02:00
LOCK_HOST = "off";
launchMini(true, false, server, username, password);
2012-04-16 23:38:00 +02:00
2012-04-17 21:13:31 +02:00
// increase priority over other Jabber clients - does not seem to work?
2012-04-17 22:32:54 +02:00
var priority = 101;
2012-04-17 21:13:31 +02:00
presenceMini(null,null,priority);
2012-04-16 23:38:00 +02:00
jappixmini_manage_roster(contacts, contacts_hash, autoapprove, autosubscribe)
}
// decrypt password if necessary
if (encrypted)
jappixmini_addon_decrypt_password(password, handler);
else
handler(password);
2012-04-13 17:05:16 +02:00
}