FLO_Twitter/home.js

498 lines
18 KiB
JavaScript

var profiles = []
var tweeterID;
var selfWebsocket,followingWebSockets = [];
var privKey;
var following;
function userDataStartUp(){
console.log("StartUp");
/*document.getElementById("sendMsgInput").addEventListener("keyup",function(event){
if(event.keyCode === 13){
event.preventDefault();
sendMsg();
}
});*/
getDatafromAPI().then(function (result) {
console.log(result);
getProfilesfromIDB().then(function (result){
profiles = arrayToObject(result);
console.log(profiles);
sessionStorage.profiles = JSON.stringify(profiles);
getuserID().then(function(result){
console.log(result);
tweeterID = result;
sessionStorage.privKey = privKey;
sessionStorage.selfID = tweeterID;
alert(`${tweeterID}\nWelcome ${profiles[tweeterID].name}`)
initselfWebSocket();
listProfiles();
getFollowinglistFromIDB().then(function(result){
following = result;
console.log(following);
displayTweetsFromIDB().then(function(result){
connectToAllFollowing();
}).catch(function(error){
console.log(error.message);
})
}).catch(function(error){
console.log(error.message);
})
}).catch(function (error) {
console.log(error.message);
});
}).catch(function (error) {
console.log(error.message);
});
}).catch(function (error) {
console.log(error.message);
});
}
function storedata(data){
return new Promise(
function(resolve, reject) {
var idb = indexedDB.open("FLO_Tweet");
idb.onerror = function(event) {
console.log("Error in opening IndexedDB!");
};
idb.onsuccess = function(event) {
var db = event.target.result;
var obs = db.transaction('profiles', "readwrite").objectStore('profiles');
objectRequest = obs.put(data);
objectRequest.onerror = function(event) {
reject(Error('Error occured: Unable to store data'));
};
objectRequest.onsuccess = function(event) {
resolve('Data saved OK');
db.close();
};
};
}
);
}
function getDatafromAPI(){
return new Promise(
function(resolve, reject) {
var addr = "F6LUnwRRjFuEW97Y4av31eLqqVMK9FrgE2";
var idb = indexedDB.open("FLO_Tweet");
idb.onerror = function(event) {
reject("Error in opening IndexedDB!");
};
idb.onupgradeneeded = function(event) {
var db = event.target.result;
var objectStore1 = db.createObjectStore("profiles",{ keyPath: 'floID' });
objectStore1.createIndex('onionAddr', 'onionAddr', { unique: false });
objectStore1.createIndex('name', 'name', { unique: false });
objectStore1.createIndex('pubKey', 'pubKey', { unique: false });
var objectStore2 = db.createObjectStore("lastTx");
var objectStore3 = db.createObjectStore("tweets",{ keyPath: 'id' });
objectStore3.createIndex('floID', 'floID', { unique: false });
objectStore3.createIndex('time', 'time', { unique: false });
objectStore3.createIndex('data', 'data', { unique: false });
var objectStore4 = db.createObjectStore("lastTweet");
var objectStore5 = db.createObjectStore("followers");
var objectStore6 = db.createObjectStore("following");
};
idb.onsuccess = function(event) {
var db = event.target.result;
//window["wait"] = addrList.length;
var lastTx = db.transaction('lastTx', "readwrite").objectStore('lastTx');
//addrList.forEach(function(addr){
console.log(addr);
new Promise(function(res,rej){
var lastTxReq = lastTx.get(addr);
lastTxReq.onsuccess = function(event){
var lasttx = event.target.result;
if(lasttx === undefined){
lasttx = 0;
}
res(lasttx);
}
}).then(function(lasttx){
var response = ajax("GET",`api/addrs/${addr}/txs`);
var nRequired = JSON.parse(response).totalItems - lasttx;
console.log(nRequired);
while(true && nRequired){
var response = ajax("GET",`api/addrs/${addr}/txs?from=0&to=${nRequired}`);
response = JSON.parse(response);
if (nRequired + lasttx != response.totalItems ){
nRequired = response.totalItems - lasttx;
continue;
}
response.items.reverse().forEach(function(tx){
try {
//if (tx.vin[0].addr != addr)
//return;
var data = JSON.parse(tx.floData).FLO_Tweet;
if(data !== undefined){
if(encrypt.getFLOIDfromPubkeyHex(data.pubKey)!=tx.vin[0].addr)
throw("PublicKey doesnot match with floID")
data = {floID : tx.vin[0].addr, onionAddr : data.onionAddr, name : data.name, pubKey:data.pubKey};
storedata(data).then(function (response) {
}).catch(function (error) {
console.log(error.message);
});
}
} catch (e) {
//console.log(e)
}
});
var obs = db.transaction('lastTx', "readwrite").objectStore('lastTx');
obs.put(response.totalItems,addr);
break;
}
db.close();
resolve('retrived data from API');
});
};
}
);
}
function getuserID(){
return new Promise(
function(resolve,reject){
privKey = sessionStorage.privKey || prompt("Enter FLO Private Key : ");
var key = new Bitcoin.ECKey(privKey);
while(key.priv == null){
privKey = prompt("Invalid FLO Private Key! Retry : ")
key = Bitcoin.ECKey(privKey);
}
key.setCompressed(true);
var userID = key.getBitcoinAddress();
if (profiles[userID] === undefined)
var reg = confirm(`${userID} is not registers to FLO Tweet!\nRegister FLO ID to this onion?`);
else if (profiles[userID].onionAddr == window.location.host)
resolve(userID)
else
var reg = confirm(`${userID} is registered to another onion!\nChange to this onion?`);
if(reg){
var name = prompt("Enter your name :");
var pubKey = key.getPubKeyHex();
if(registerID(userID,window.location.host,privKey,pubKey,name)){
profiles[userID] = {onionAddr : window.location.host, name : name, pubKey : pubKey};
resolve(userID);
}
}
reject(`Unable to bind ${userID} to this onionAddress!\nTry again later!`);
}
);
}
function getProfilesfromIDB(){
return new Promise(
function(resolve,reject){
var idb = indexedDB.open("FLO_Tweet");
idb.onerror = function(event) {
reject("Error in opening IndexedDB!");
};
idb.onsuccess = function(event) {
var db = event.target.result;
var obs = db.transaction("profiles", "readwrite").objectStore("profiles");
var getReq = obs.getAll();
getReq.onsuccess = function(event){
resolve(event.target.result);
}
getReq.onerror = function(event){
reject('Unable to read profiles!')
}
db.close();
};
}
);
}
function readMsgfromIDB(){
return new Promise(
function(resolve,reject){
var disp = document.getElementById("conversation");
for(floID in profiles){
var createLi = document.createElement('div');
createLi.setAttribute("id", floID);
createLi.setAttribute("class", "message-inner");
createLi.style.display = 'none';
disp.appendChild(createLi);
}
var idb = indexedDB.open("FLO_Tweet",2);
idb.onerror = function(event) {
reject("Error in opening IndexedDB!");
};
idb.onupgradeneeded = function(event) {
var objectStore = event.target.result.createObjectStore("messages",{ keyPath: 'time' });
objectStore.createIndex('text', 'text', { unique: false });
objectStore.createIndex('floID', 'floID', { unique: false });
objectStore.createIndex('type', 'type', { unique: false });
};
idb.onsuccess = function(event) {
var db = event.target.result;
var obs = db.transaction("messages", "readwrite").objectStore("messages");
obs.openCursor().onsuccess = function(event) {
var cursor = event.target.result;
if(cursor) {
var chat = document.getElementById(cursor.value.floID);
if(cursor.value.type == "R"){
var msgdiv = document.createElement('div');
msgdiv.setAttribute("class", "row message-body");
msgdiv.innerHTML = `<div class="col-sm-12 message-main-receiver">
<div class="receiver">
<span class="message-text">
${cursor.value.text}
</span>
<span class="message-time pull-right">
${getTime(cursor.value.time)}
</span>
</div>
</div>`;
chat.appendChild(msgdiv);
}else if(cursor.value.type == "S"){
var msgdiv = document.createElement('div');
msgdiv.setAttribute("class", "row message-body");
msgdiv.innerHTML = `<div class="col-sm-12 message-main-sender">
<div class="sender">
<span class="message-text">${cursor.value.text}
</span>
<span class="message-time pull-right">
${getTime(cursor.value.time)}
</span>
</div>
</div>`;
chat.appendChild(msgdiv);
}
cursor.continue();
} else {
console.log('Entries all displayed.');
resolve("Read Msg from IDB");
}
};
db.close();
};
}
);
}
function initselfWebSocket(){
selfWebsocket = new WebSocket("ws://"+location.host+"/ws");
selfWebsocket.onopen = function(evt){
console.log("Connecting");
var pass = sessionStorage.serverPass || prompt("Enter server password :");
selfWebsocket.send("$"+pass);
sessionStorage.serverPass = pass;
};
selfWebsocket.onclose = function(evt){
console.log("DISCONNECTED");
};
selfWebsocket.onmessage = function(evt){
console.log(evt.data);
if(evt.data == "$Access Denied!"){
var pass = prompt("Access Denied! reEnter server password :");
selfWebsocket.send("$"+pass);
sessionStorage.serverPass = pass;
}else if(evt.data == "$Access Granted!")
alert("Access Granted!")
else{
try{
data = JSON.parse(evt.data);
if(data.follow && encrypt.verify(selfID, data.sign, profiles[data.floID].pubKey)){
var idb = indexedDB.open("FLO_Tweet");
idb.onsuccess = function(event) {
var db = event.target.result;
var obs = db.transaction("followers", "readwrite").objectStore("followers");
obs.add(data.sign,data.floID);
db.close();
};
selfWebsocket.send(`F${data.floID}`);
}else if(data.unfollow && encrypt.verify(selfID, data.sign, profiles[data.floID].pubKey)){
var idb = indexedDB.open("FLO_Tweet");
idb.onsuccess = function(event) {
var db = event.target.result;
var obs = db.transaction("followers", "readwrite").objectStore("followers");
obs.delete(data.floID);
db.close();
};
selfWebsocket.send(`U${data.floID}`);
}
}catch(error){
console.log(error.message);
}
}
};
selfWebsocket.onerror = function(evt){
console.log(evt);
};
}
function postTweet(){
var tweetBox = document.getElementById("tweetBox");
var tweet = tweetBox.value;
tweetBox.value = "";
var time = (new Date).getTime();
var sign = encrypt.sign(tweet,privKey);
var data = JSON.stringify({floID:tweeterID,time:time,tweet:tweet,sign:sign});
console.log(data);
selfWebsocket.send(data);
createTweetElement(tweeterID,time,tweet);
getLastTweetCount(tweeterID).then(function(result){
storeTweet({floID:tweeterID,time:time,data:tweet},result+1);
}).catch(function(error){
console.log(error.message);
});
}
function storeTweet(data,id){
var idb = indexedDB.open("FLO_Tweet");
idb.onerror = function(event) {
console.log("Error in opening IndexedDB!");
};
idb.onsuccess = function(event) {
var db = event.target.result;
var obs = db.transaction("tweets", "readwrite").objectStore("tweets");
data.id = `${data.time}_${data.floID}`;
obs.add(data);
var obsL = db.transaction("lastTweet", "readwrite").objectStore("lastTweet");
obsL.put(id,data.floID);
db.close();
};
}
function getFollowinglistFromIDB(){
return new Promise(
function(resolve,reject){
var idb = indexedDB.open("FLO_Tweet");
idb.onerror = function(event) {
reject("Error in opening IndexedDB!");
};
idb.onsuccess = function(event) {
var db = event.target.result;
var obs = db.transaction("following", "readwrite").objectStore("following");
var getReq = obs.getAllKeys();
getReq.onsuccess = function(event){
resolve(event.target.result);
}
getReq.onerror = function(event){
reject('Unable to read following list!')
}
db.close();
};
}
);
}
function displayTweetsFromIDB(){
return new Promise(
function(resolve,reject){
var idb = indexedDB.open("FLO_Tweet");
idb.onerror = function(event) {
reject("Error in opening IndexedDB!");
};
idb.onsuccess = function(event) {
var db = event.target.result;
var obs = db.transaction("tweets", "readwrite").objectStore("tweets");
var curReq = obs.openCursor();
curReq.onsuccess = function(event) {
var cursor = event.target.result;
if(cursor) {
//console.log(cursor.value)
if(cursor.value.floID == tweeterID || following.includes(cursor.value.floID))
createTweetElement(cursor.value.floID,cursor.value.time,cursor.value.data);
cursor.continue();
}else{
resolve("Displayed Tweets from IDB!");
}
}
curReq.onerror = function(event){
reject("Error in Reading tweets from IDB!");
}
db.close();
};
}
);
}
function createTweetElement(floID,time,tweet){
var tweetDisplay = document.getElementById("tweetsContainer");
var element = document.createElement("div");
element.setAttribute("class", "media");
element.innerHTML = `
<div class="media-body">
<h4 class="media-heading">${profiles[floID].name} <small>@${floID}</small></h4>
<p>${tweet}</p>
<ul class="nav nav-pills nav-pills-custom">
<li><a href="#"><span class="glyphicon glyphicon-share-alt"></span></a></li>
<li><a href="#"><span class="glyphicon glyphicon-retweet"></span></a></li>
<li><a href="#"><span class="glyphicon glyphicon-star"></span></a></li>
<li><a href="#"><span class="glyphicon glyphicon-option-horizontal"></span></a></li>
<li><span class="timestamp pull-right">${getTime(time)}</span></li>
</ul>
</div>`;
tweetDisplay.insertBefore(element, tweetDisplay.firstChild);
}
function connectToAllFollowing(){
console.log("Connecting to All following servers...")
for(i=0;i<following.length;i++){
var floid = following[i];
followingWebSockets[floid] = new WebSocket("ws://"+profiles[floid].onionAddr+"/ws");
followingWebSockets[floid].onopen = function(ev){
console.log(`Connected to ${floid} Server!`);
getLastTweetCount(floid).then(function(result){
followingWebSockets[floid].send(`>${result}`);
}).catch(function(error){
console.log(error.message);
});
};
followingWebSockets[floid].onerror = function(ev) {
console.log(`${floid} Server is offline!`);
};
followingWebSockets[floid].onclose = function(ev) {
console.log(`Disconnected from ${floid} Server!`);
};
followingWebSockets[floid].onmessage = function(evt){
console.log(evt.data);
try{
var data = JSON.parse(evt.data);
var id = data.id;
data = data.data;
if( floid!=data.floID || !encrypt.verify(data.tweet,data.sign,profiles[floid].pubKey))
return
storeTweet({floID:data.floID,time:data.time,data:data.tweet},id);
createTweetElement(data.floID,data.time,data.tweet);
}catch(error){
console.log(error.message);
}
};
}
}
function getLastTweetCount(floid){
return new Promise(
function(resolve,reject){
var idb = indexedDB.open("FLO_Tweet");
idb.onsuccess = function(event) {
var db = event.target.result;
var lastTweet = db.transaction('lastTweet', "readwrite").objectStore('lastTweet');
var lastTweetReq = lastTweet.get(floid);
lastTweetReq.onsuccess = function(event){
var result = event.target.result;
if(result === undefined)
result = 0;
resolve(result);
}
db.close();
};
}
);
}