forked from friendica/friendica-addons
251 lines
7.4 KiB
JavaScript
251 lines
7.4 KiB
JavaScript
function jappixmini_addon_xor(str1, str2) {
|
|
if (str1.length != str2.length) throw "not same length";
|
|
|
|
encoded = "";
|
|
|
|
for (i=0; i<str1.length;i++) {
|
|
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) {
|
|
if (!password) return;
|
|
|
|
salt1 = "h8doCRekWto0njyQohKpdx6BN0UTyC6N";
|
|
salt2 = "jdX8OwFC1kWAq3s9uOyAcE8g3UNNO5t3";
|
|
|
|
client_secret1 = str_sha1(salt1+password);
|
|
client_secret2 = str_sha1(salt2+password);
|
|
client_secret = client_secret1 + client_secret2;
|
|
|
|
setPersistent('jappix-mini', 'client-secret', client_secret);
|
|
console.log("client secret set");
|
|
}
|
|
|
|
function jappixmini_addon_get_client_secret(callback) {
|
|
client_secret = getPersistent('jappix-mini', 'client-secret');
|
|
if (client_secret===null) {
|
|
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:50px;">Retype your Friendica password for chatting:<br></div>');
|
|
|
|
input = $('<input type="password" id="jappixmini-password-query-input">')
|
|
div.append(input);
|
|
|
|
button = $('<input type="button" value="OK" id="jappixmini-password-query-button">');
|
|
div.append(button);
|
|
|
|
$("body").append(div);
|
|
}
|
|
|
|
button.click(function(){
|
|
password = $("#jappixmini-password-query-input").val();
|
|
jappixmini_addon_set_client_secret(password);
|
|
div.remove();
|
|
|
|
client_secret = getPersistent('jappix-mini', 'client-secret');
|
|
callback(client_secret);
|
|
});
|
|
}
|
|
else {
|
|
callback(client_secret);
|
|
}
|
|
}
|
|
|
|
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";
|
|
}
|
|
|
|
// xor password with secret
|
|
encrypted_password = jappixmini_addon_xor(client_secret, password);
|
|
|
|
encrypted_password = encodeURI(encrypted_password)
|
|
callback(encrypted_password);
|
|
});
|
|
}
|
|
|
|
function jappixmini_addon_decrypt_password(encrypted_password, callback) {
|
|
encrypted_password = decodeURI(encrypted_password);
|
|
|
|
jappixmini_addon_get_client_secret(function(client_secret){
|
|
// xor password with secret
|
|
password = jappixmini_addon_xor(client_secret, encrypted_password);
|
|
|
|
// remove \0
|
|
first_null = password.indexOf("\0")
|
|
if (first_null==-1) throw "Decrypted password does not contain \\0";
|
|
password = password.substr(0, first_null);
|
|
|
|
callback(password);
|
|
});
|
|
}
|
|
|
|
function jappixmini_manage_roster(contacts, autoapprove, autosubscribe) {
|
|
// 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();
|
|
|
|
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.
|
|
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");
|
|
}
|
|
|
|
if (approve) {
|
|
acceptSubscribe(xid, contacts[xid]);
|
|
console.log("Accepted "+xid+" for chat.");
|
|
}
|
|
});
|
|
|
|
// autosubscribe
|
|
if (!autosubscribe) return;
|
|
|
|
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() {
|
|
xid = $(this).attr("jid");
|
|
name = $(this).attr("name");
|
|
subscription = $(this).attr("subscription");
|
|
|
|
// ignore accounts not in the list
|
|
if (contacts[xid]===undefined) return;
|
|
|
|
// add to Friendica group if necessary
|
|
groups = [];
|
|
$(this).find('group').each(function() {
|
|
var group_text = $(this).text();
|
|
if(group_text) groups.push(group_text);
|
|
});
|
|
|
|
if ($.inArray("Friendica", groups)==-1) {
|
|
console.log("Add "+xid+" to Friendica group.");
|
|
groups.push("Friendica");
|
|
sendRoster(xid, null, null, groups);
|
|
console.log("Added "+xid+" to Friendica group.");
|
|
}
|
|
|
|
// authorize if necessary
|
|
if (subscription=="to") {
|
|
sendSubscribe(xid, 'subscribed');
|
|
}
|
|
|
|
// 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]");
|
|
|
|
con.send(presence);
|
|
console.log("subscribed to "+xid);
|
|
|
|
// 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);
|
|
console.log("added to roster: "+xid);
|
|
}
|
|
});
|
|
}
|
|
|
|
function jappixmini_addon_subscribe() {
|
|
if (!window.con) {
|
|
alert("Not connected.");
|
|
return;
|
|
}
|
|
|
|
xid = prompt("Jabber address");
|
|
sendSubscribe(xid, "subscribe");
|
|
}
|
|
|
|
function jappixmini_addon_start(server, username, proxy, bosh, encrypted, password, nickname, contacts, autoapprove, autosubscribe) {
|
|
handler = function(password){
|
|
// check if settings have changed, reinitialize jappix mini if this is the case
|
|
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);
|
|
|
|
saved_identifier = getDB("jappix-mini", "settings_identifier");
|
|
if (saved_identifier != settings_identifier) removeDB('jappix-mini', 'dom');
|
|
setDB("jappix-mini", "settings_identifier", settings_identifier);
|
|
|
|
// set HOST_BOSH
|
|
if (proxy)
|
|
HOST_BOSH = proxy+"?host_bosh="+encodeURI(bosh);
|
|
else
|
|
HOST_BOSH = bosh;
|
|
|
|
// start jappix mini
|
|
MINI_NICKNAME = nickname;
|
|
LOCK_HOST = "off";
|
|
launchMini(true, false, server, username, password);
|
|
|
|
// increase priority over other Jabber clients
|
|
priority = 101;
|
|
sendPresence(null,null,priority);
|
|
|
|
jappixmini_manage_roster(contacts, autoapprove, autosubscribe)
|
|
}
|
|
|
|
// decrypt password if necessary
|
|
if (encrypted)
|
|
jappixmini_addon_decrypt_password(password, handler);
|
|
else
|
|
handler(password);
|
|
}
|