Merge pull request #2 from sairajzero/master

This commit is contained in:
Sai Raj 2019-08-09 11:51:06 +05:30 committed by GitHub
commit 196ae1c30e
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
11 changed files with 7745 additions and 7627 deletions

6
.gitattributes vendored Normal file
View File

@ -0,0 +1,6 @@
*.gitattributes linguist-vendored
util/mongoose.c linguist-vendored
util/mongoose.h linguist-vendored
app/web/init.js linguist-vendored
.gitattributes export-ignore

View File

@ -7,6 +7,15 @@ if (!window.indexedDB) {
window.alert("Your browser doesn't support a stable version of IndexedDB.")
}
const adminID = "FMabh7gTSyKPAb2Wi9sK5CBhV8nVFk783i";
if(blockchain == "FLO")
var api_url = `https://flosight.duckdns.org/`;
else if(blockchain == "FLO_TEST")
var api_url = `https://testnet-flosight.duckdns.org/`;
var supernodeKBucket;
var superNodeList;
var months = ['Jan','Feb','Mar','Apr','May','Jun','Jul','Aug','Sep','Oct','Nov','Dec'];
var encrypt = {
@ -14,7 +23,7 @@ var encrypt = {
p: BigInteger("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFC2F", 16),
exponent1: function () {
return encrypt.p.add(BigInteger.ONE).divide(BigInteger("4"))
return this.p.add(BigInteger.ONE).divide(BigInteger("4"))
},
calculateY: function (x) {
@ -147,7 +156,7 @@ var encrypt = {
getPubKeyHex: function(privateKeyHex){
var key = new Bitcoin.ECKey(privateKeyHex);
if(key.priv == null){
alert("Invalid Private key");
console.log("Invalid Private key");
return;
}
key.setCompressed(true);
@ -159,6 +168,34 @@ var encrypt = {
var floID = key.getBitcoinAddress();
return floID;
},
validateAddr: function (value) {
try{
var addr = new Bitcoin.Address(value);
if (addr == value)
return true;
else
return false;
}catch(error){
return false;
}
},
verifyWIF: function (wif,addr){
try {
var key = new Bitcoin.ECKey(wif);
if(key.priv == null){
return false;
}
key.setCompressed(true);
var bitcoinAddress = key.getBitcoinAddress();
if (addr == bitcoinAddress)
return true;
else
return false;
}
catch (error) {
console.log(error);
}
},
sign: function (msg, privateKeyHex) {
var key = new Bitcoin.ECKey(privateKeyHex);
key.setCompressed(true);
@ -255,14 +292,354 @@ function getTime(time){
function logout(){
sessionStorage.clear();
location.reload();
window.location.href = "index.html";
}
var supernodeKBucket;
var superNodeList;
/*Refresh profile and superNode data from API */
function ajax(method, uri){
var request = new XMLHttpRequest();
var url = `${api_url}/${uri}`
console.log(url)
var result;
request.open(method,url , false);
request.onload = function () {
if (request.readyState == 4 && request.status == 200)
result = this.response;
else {
console.log('error');
result = false;
}
};
request.send();
console.log(result);
return result;
}
function reloadInitData(){
refreshAPIdata.then(result => {
console.log(result);
sessionStorage.profiles = JSON.stringify(profiles);
sessionStorage.superNodeList = JSON.stringify(Array.from(superNodeList));
kBucketObj.launchKBucket().then(result => {
console.log(result)
}).catch(error => {
console.log(error);
});
}).catch(error => {
console.log(error);
});
}
function refreshAPIdata(){
return new Promise((resolve,reject) => {
var addr = adminID;
var idb = indexedDB.open("FLO_Tweet");
idb.onerror = (event) => { reject("Error in opening IndexedDB!") };
idb.onsuccess = (event) => {
var db = event.target.result;
var lastTx = db.transaction('lastTx', "readwrite").objectStore('lastTx');
console.log(addr);
new Promise((res,rej) => {
var lastTxReq = lastTx.get(addr);
lastTxReq.onsuccess = (event) => {
var lasttx = event.target.result;
if(lasttx === undefined){
lasttx = 0;
}
res(lasttx);
}
}).then(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(tx => {
try {
if (tx.vin[0].addr == addr){
var data = JSON.parse(tx.floData).FLO_Tweet_SuperNode;
if(data !== undefined){
if(data.addNodes)
for(var i=0; i<data.addNodes.length; i++)
superNodeList.add(data.addNodes[i])
if(data.removeNodes)
for(var i=0; i<data.removeNodes.length; i++)
superNodeList.delete(data.removeNodes[i])
storeSuperNodeData(data).then(function (response) {
}).catch(error => {
console.log(error);
});
}
}else{
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};
profiles[data.floID] = {onionAddr : data.onionAddr, name : data.name, pubKey : data.pubKey};
storeProfile(data).then(function (response) {
}).catch(error => {
console.log(error);
});
}
}
} catch (error) {
//console.log(error)
}
});
var obs = db.transaction('lastTx', "readwrite").objectStore('lastTx');
obs.put(response.totalItems,addr);
break;
}
db.close();
resolve('retrived data from API');
});
};
});
}
/* Common IDB functions */
function storeProfile(data){
return new Promise((resolve,reject) => {
var idb = indexedDB.open("FLO_Tweet");
idb.onerror = (event) => { console.log("Error in opening IndexedDB!") };
idb.onsuccess = (event) => {
var db = event.target.result;
var obs = db.transaction('profiles', "readwrite").objectStore('profiles');
objectRequest = obs.put(data);
objectRequest.onerror = (event) => { reject(Error('Error occured: Unable to store data'))};
objectRequest.onsuccess = (event) => { resolve('Data saved OK') };
db.close();
};
});
}
function storeSuperNodeData(data){
return new Promise((resolve,reject) => {
var idb = indexedDB.open("FLO_Tweet");
idb.onerror = (event) => { reject("Error in opening IndexedDB!"); };
idb.onsuccess = (event) => {
var db = event.target.result;
var obs = db.transaction('superNodes', "readwrite").objectStore('superNodes');
if(data.addNodes)
for(var i=0; i<data.addNodes.length; i++)
obs.add(true,data.addNodes[i])
if(data.removeNodes)
for(var i=0; i<data.removeNodes.length; i++)
obs.delete(data.removeNodes[i])
db.close();
resolve('Updated superNodes list in IDB');
};
});
}
function storeTweet(data,tid){
var idb = indexedDB.open("FLO_Tweet");
idb.onerror = (event) => { console.log("Error in opening IndexedDB!") };
idb.onsuccess = (event) => {
var db = event.target.result;
var obs = db.transaction("tweets", "readwrite").objectStore("tweets");
data.tweetID = `${data.time}_${data.floID}`;
data.tid = tid;
obs.add(data);
var obsL = db.transaction("lastTweet", "readwrite").objectStore("lastTweet");
obsL.put(tid,data.floID);
db.close();
};
}
function storeMsg(data){
var idb = indexedDB.open("FLO_Tweet");
idb.onerror = (event) => { console.log("Error in opening IndexedDB!") };
idb.onsuccess = (event) => {
var db = event.target.result;
var obs = db.transaction("messages", "readwrite").objectStore("messages");
data.msgID = `${data.time}_${data.floID}`;
obs.add(data);
db.close();
};
}
/* SuperNode functions */
function sendDataToSuperNode(floID,data){
kBucketObj.determineClosestSupernode(floID).then(result=>{
var superNodeWS = new WebSocket("ws://"+profiles[result[0].floID].onionAddr+"/ws");
superNodeWS.onopen = function(ev){
console.log(`Connected to ${floID}'s SuperNode!`);
superNodeWS.send(data);
};
superNodeWS.onerror = function(ev) {console.log(`${floid}'s SuperNode is offline!`);};
superNodeWS.onclose = function(ev) {console.log(`Disconnected from ${floid}'s SuperNode!`);};
}).catch(e => {
console.log(e.message);
});
}
function superNodeMode(data){
if(data.reqNewTweets){
kBucketObj.determineClosestSupernode(data.floID).then(result => {
if(result[0].floID == selfID)
SuperNode_sendTweetsFromIDB(data.floID,data.tid,data.requestor);
}).catch(error => {
console.log(error);
});
}else if(data.newSuperNodeTweet){
kBucketObj.determineClosestSupernode(data.floID).then(result => {
if(result[0].floID == selfID)
SuperNode_storeSuperNodeTweet(data.data,data.tid);
}).catch(error => {
console.log(error);
});
}else if(data.viaSuperNodeMsg){
kBucketObj.determineClosestSupernode(data.to).then(result => {
if(result[0].floID == selfID)
SuperNode_storeViaSuperNodeMsg(data.from,data.to,data.data);
}).catch(error => {
console.log(error);
});
}else if(data.viaMsgreq){
kBucketObj.determineClosestSupernode(data.floID).then(result => {
if(result[0].floID == selfID)
SuperNode_sendviaMsgFromIDB(data.floID);
}).catch(error => {
console.log(error);
});
}
}
function SuperNode_sendTweetsFromIDB(floID,tid,requestor){
return new Promise((resolve,reject) => {
var requestorWS = new WebSocket("ws://"+profiles[requestor].onionAddr+"/ws");
requestorWS.onopen = (event) => {
console.log(`sending ${floID} tweets to ${requestor} Server!`);
var idb = indexedDB.open("FLO_Tweet",2);
idb.onerror = (event) => { reject("Error in opening IndexedDB!") };
idb.onupgradeneeded = (event) => {
var objectStore1 = event.target.result.createObjectStore("superNodeTweet",{ keyPath: 'tweetID' });
objectStore1.createIndex('floID', 'floID', { unique: false });
objectStore1.createIndex('tid', 'tid', { unique: false });
objectStore1.createIndex('data', 'data', { unique: false });
var objectStore2 = event.target.result.createObjectStore("viaSuperNodeMsg",{ keyPath: 'id',autoIncrement:true });
objectStore2.createIndex('from', 'from', { unique: false });
objectStore2.createIndex('to', 'to', { unique: false });
objectStore2.createIndex('data', 'data', { unique: false });
}
idb.onsuccess = (event) => {
var db = event.target.result;
var obs = db.transaction("superNodeTweet", "readwrite").objectStore("superNodeTweet");
var curReq = obs.openCursor();
curReq.onsuccess = (event) => {
var cursor = event.target.result;
if(cursor) {
if(cursor.value.floID == floID && cursor.value.tid > tid){
data = JSON.stringify({fromSuperNode:true, floID:cursor.value.floID,tid:cursor.value.tid,data:cursor.value.data})
requestorWS.send(data);
}
cursor.continue();
}else{
resolve("Displayed Tweets from IDB!");
}
}
curReq.onerror = (event) => { reject("Error in Reading tweets from IDB!") }
db.close();
};
};
requestorWS.onerror = (event) => { console.log(`${requestor} Server is offline!`) };
requestorWS.onclose = (event) => { console.log(`Disconnected from ${requestor} Server!`) };
});
}
function SuperNode_storeSuperNodeTweet(data,tid){
var idb = indexedDB.open("FLO_Tweet",2);
idb.onerror = (event) => { console.log("Error in opening IndexedDB!") };
idb.onupgradeneeded = (event) => {
var objectStore1 = event.target.result.createObjectStore("superNodeTweet",{ keyPath: 'tweetID' });
objectStore1.createIndex('floID', 'floID', { unique: false });
objectStore1.createIndex('tid', 'tid', { unique: false });
objectStore1.createIndex('data', 'data', { unique: false });
var objectStore2 = event.target.result.createObjectStore("viaSuperNodeMsg",{ keyPath: 'id',autoIncrement:true });
objectStore2.createIndex('from', 'from', { unique: false });
objectStore2.createIndex('to', 'to', { unique: false });
objectStore2.createIndex('data', 'data', { unique: false });
}
idb.onsuccess = (event) => {
var db = event.target.result;
var obs = db.transaction("superNodeTweet", "readwrite").objectStore("superNodeTweet");
var parsedData = JSON.parse(data);
var tweetID = ''+parsedData.floID+'_'+parsedData.time;
obs.add({tweetID:tweetID,floID:parsedData.floID,tid:tid,data:data});
db.close();
};
}
function SuperNode_storeViaSuperNodeMsg(from,to,data){
var idb = indexedDB.open("FLO_Tweet",2);
idb.onerror = (event) => { console.log("Error in opening IndexedDB!") };
idb.onupgradeneeded = (event) => {
var objectStore1 = event.target.result.createObjectStore("superNodeTweet",{ keyPath: 'tweetID' });
objectStore1.createIndex('floID', 'floID', { unique: false });
objectStore1.createIndex('tid', 'tid', { unique: false });
objectStore1.createIndex('data', 'data', { unique: false });
var objectStore2 = event.target.result.createObjectStore("viaSuperNodeMsg",{ keyPath: 'id',autoIncrement :true });
objectStore2.createIndex('from', 'from', { unique: false });
objectStore2.createIndex('to', 'to', { unique: false });
objectStore2.createIndex('data', 'data', { unique: false });
}
idb.onsuccess = (event) => {
var db = event.target.result;
var obs = db.transaction("viaSuperNodeMsg", "readwrite").objectStore("viaSuperNodeMsg");
obs.add({from:from,to:to,data:data});
db.close();
};
}
function SuperNode_sendviaMsgFromIDB(floID){
var receiverWS = new WebSocket("ws://"+profiles[floID].onionAddr+"/ws");
receiverWS.onopen = (event) => {
var idb = indexedDB.open("FLO_Tweet",2);
idb.onerror = (event) => { console.log("Error in opening IndexedDB!") };
idb.onupgradeneeded = (event) => {
var objectStore1 = event.target.result.createObjectStore("superNodeTweet",{ keyPath: 'tweetID' });
objectStore1.createIndex('floID', 'floID', { unique: false });
objectStore1.createIndex('tid', 'tid', { unique: false });
objectStore1.createIndex('data', 'data', { unique: false });
var objectStore2 = event.target.result.createObjectStore("viaSuperNodeMsg",{ keyPath: 'id',autoIncrement:true });
objectStore2.createIndex('from', 'from', { unique: false });
objectStore2.createIndex('to', 'to', { unique: false });
objectStore2.createIndex('data', 'data', { unique: false });
};
idb.onsuccess = (event) => {
var db = event.target.result;
var obs = db.transaction("viaSuperNodeMsg", "readwrite").objectStore("viaSuperNodeMsg");
obs.openCursor().onsuccess = (event) => {
var cursor = event.target.result;
if(cursor) {
if(cursor.value.to == floID){
receiverWS.send(cursor.value.data);
cursor.delete();
}
cursor.continue();
}else{
console.log('Sent All messages to '+floID)
}
}
db.close();
};
};
receiverWS.onerror = (event) => { console.log('Connection Error to '+floID) };
receiverWS.onclose = (event) => { console.log('Disconnected from '+floID) };
}
/* ---end of app.js --- */
/*Kademlia DHT K-bucket implementation as a binary tree.*/
if (typeof reactor == "undefined" || !reactor) {
if (typeof reactor == "undefined" || !reactor) {
(function () {
function Event(name) {
@ -317,25 +694,6 @@ reactor.addEventListener('bucket_full', function (someObject) {
console.log('Bucket full ' + someObject);
});
/*
//Sample Usage
//Creating and defining the event
reactor.registerEvent('big bang');
reactor.addEventListener('big bang', function(someObject){
console.log('This is big bang listener yo!'+ someObject.a);
});
//Firing the event
reactor.dispatchEvent('big bang');
reactor.dispatchEvent('big bang',{a:1});
reactor.dispatchEvent('big bang',{a:55});
*/
//Checking if existing NodeID can be used
//This first block of if will initialize the configuration of KBucket
//Add Events, Messaging between different K-Buckets, and attach relevant distributed data
/**
* @param {Uint8Array} array1
@ -753,7 +1111,7 @@ reactor.dispatchEvent('big bang',{a:55});
kBucketObj = {
decodeBase58Address: function (blockchain, address) {
decodeBase58Address: function (address) {
let k = bitjs.Base58.decode(address)
k.shift()
k.splice(-4, 4)
@ -764,12 +1122,12 @@ kBucketObj = {
try {
//const master_flo_pubKey = localbitcoinplusplus.master_configurations.masterFLOPubKey;
const master_flo_addr = adminID;
const SuKBucketId = this.floIdToKbucketId(crypto, master_flo_addr);
const SuKBucketId = this.floIdToKbucketId(master_flo_addr);
const SukbOptions = { localNodeId: SuKBucketId }
supernodeKBucket = new BuildKBucket(SukbOptions);
for(var i=0; i<superNodeList.length ; i++){
this.addNewUserNodeInKbucket(crypto,superNodeList[i],supernodeKBucket)
}
var SNArray = Array.from(superNodeList);
for(var i=0; i<SNArray.length ; i++)
this.addNewUserNodeInKbucket(SNArray[i],supernodeKBucket)
resolve('SuperNode KBucket formed');
} catch (error) {
reject(error);
@ -783,7 +1141,7 @@ kBucketObj = {
try {
let flo_id = bitjs.pubkey2address(pubKey);
let kname = `SKBucket_${pubKey}`;
const KBucketId = this.floIdToKbucketId(crypto, flo_id)
const KBucketId = this.floIdToKbucketId(flo_id)
const kbOptions = { localNodeId: KBucketId }
window[kname] = new BuildKBucket(kbOptions);
resolve(true);
@ -800,18 +1158,18 @@ kBucketObj = {
};
KB.add(contact)
},
addNewUserNodeInKbucket: function(blockchain, address, KB=supernodeKBucket) {
addNewUserNodeInKbucket: function(address, KB=supernodeKBucket) {
let decodedId = address;
try {
decodedId = this.floIdToKbucketId(blockchain, address);
decodedId = this.floIdToKbucketId(address);
} catch(e) {
decodedId = address;
}
const addNewUserNode = this.addContact(decodedId, address, KB);
return {decodedId:decodedId, address:address};
},
floIdToKbucketId: function (blockchain, address) {
const decodedId = this.decodeBase58Address(blockchain, address);
floIdToKbucketId: function (address) {
const decodedId = this.decodeBase58Address(address);
const nodeIdBigInt = new BigInteger(decodedId, 16);
const nodeIdBytes = nodeIdBigInt.toByteArrayUnsigned();
const nodeIdNewInt8Array = new Uint8Array(nodeIdBytes);
@ -835,7 +1193,7 @@ kBucketObj = {
let pubKeyBytes = Crypto.util.hexToBytes(pubKey);
return Crypto.util.bytesToBase64(pubKeyBytes);
},
restoreKbucket: function(flo_addr, blockchain="FLO_TEST", KB=KBucket) {
restoreKbucket: function(flo_addr, KB=KBucket) {
return new Promise((resolve, reject)=>{
readAllDB('kBucketStore')
.then(dbObject => {
@ -846,7 +1204,7 @@ kBucketObj = {
dbObject
.filter(f=>!su_flo_addr_array.includes(f.data.id))
.map(dbObj=>{
this.addNewUserNodeInKbucket(blockchain, flo_addr, dbObj.data, KB);
this.addNewUserNodeInKbucket(flo_addr, dbObj.data, KB);
});
} else {
reject(`Failed to restore kBucket.`);
@ -862,7 +1220,7 @@ kBucketObj = {
let supernodeSeedsObj = JSON.parse(supernodeSeeds);
Object.entries(supernodeSeedsObj).map(seedObj=>{
let kbuck = this.addNewUserNodeInKbucket(crypto, seedObj[1].kbucketId,
let kbuck = this.addNewUserNodeInKbucket(seedObj[1].kbucketId,
{ id: seedObj[1].kbucketId }, supernodeKBucket);
});
@ -940,7 +1298,7 @@ kBucketObj = {
}
let isFloIdUint8 = flo_addr instanceof Uint8Array;
if (!isFloIdUint8) {
flo_addr = this.floIdToKbucketId(crypto, flo_addr);
flo_addr = this.floIdToKbucketId(flo_addr);
}
const closestSupernode = supernodeKBucket.closest(flo_addr, n);
resolve(closestSupernode);
@ -951,49 +1309,5 @@ kBucketObj = {
return false;
}
})
},
addClosestSupernodeInDB: function(flo_addr, KB=KBucket) {
return new Promise(async (resolve, reject)=>{
const supernodeSeeds = localbitcoinplusplus.master_configurations.supernodeSeeds;
if (typeof supernodeSeeds !== "object") reject("Failed to get supernode seeds.");
let supernodeSeedsObj = JSON.parse(supernodeSeeds);
Object.entries(supernodeSeedsObj).map(seedObj=>{
console.log(seedObj);
this.addNewUserNodeInKbucketAndDB(
crypto, seedObj[1].kbucketId,
{ id: seedObj[1].kbucketId });
});
let primarySu = await this.determineClosestSupernode(flo_addr);
let nearestSupernode = await this.determineClosestSupernode(flo_addr="", n=1, supernodeKBucket, primarySu[0].data.id);
let nearestSupernodeIds = nearestSupernode.map(f=>f.data.id);
let supernodeSeedsArray = Object.values(supernodeSeedsObj)
.filter(seed=>nearestSupernodeIds.includes(seed.kbucketId))
.sort(function(a, b){
return nearestSupernodeIds.indexOf(a.kbucketId) - nearestSupernodeIds.indexOf(b.kbucketId);
});
if (supernodeSeedsArray.length>0) {
resolve(supernodeSeedsArray);
} else {
reject(false);
}
})
}
}
function sendDataToSuperNode(floID,data){
kBucketObj.determineClosestSupernode(floID).then(result=>{
var superNodeWS = new WebSocket("ws://"+profiles[result[0].floID].onionAddr+"/ws");
superNodeWS.onopen = function(ev){
console.log(`Connected to ${floID}'s SuperNode!`);
superNodeWS.send(data);
};
superNodeWS.onerror = function(ev) {console.log(`${floid}'s SuperNode is offline!`);};
superNodeWS.onclose = function(ev) {console.log(`Disconnected from ${floid}'s SuperNode!`);};
}).catch(e => {
console.log(e.message);
});
}
}

View File

@ -8,12 +8,12 @@
<link rel="stylesheet" href="styles.css">
<!-- Font Awesome File -->
<script type="text/javascript" src="registerID.js"></script>
<script type="text/javascript" src="init.js"></script>
<script type="text/javascript" src="app.js"></script>
<script type="text/javascript" src="home.js"></script>
</head>
<body onload = "userDataStartUp();">
<body onload = "viewHome();">
<div class="navbar navbar-default navbar-static-top">
<div class="container">
@ -35,10 +35,13 @@
<input type="text" class="form-control-nav" id="search" aria-describedby="search1">
<span class="glyphicon glyphicon-search form-control-feedback" aria-hidden="true"></span>
</div>
<button class="btn btn-default btn-sm" onclick="reloadInitData()">
<span class="glyphicon glyphicon-refresh"> </span>
</button>
<button class="btn btn-default btn-sm" onclick="logout()">
<span class="glyphicon glyphicon-log-out"> </span> Log out
</button>
</div>
</div>
</div>

View File

@ -1,317 +1,65 @@
var profiles = []
var selfID;
var profiles, following;
var selfWebsocket,followingWebSockets = [];
var privKey;
var following;
var privKey, modSuperNode, selfID;
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);
getSuperNodeListfromIDB().then(function(result){
console.log(result)
superNodeList = result;
sessionStorage.superNodeList = JSON.stringify(superNodeList);
kBucketObj.launchKBucket().then(function(result){
console.log(result)
getuserID().then(function(result){
console.log(result);
selfID = result;
if(superNodeList.includes(selfID))
modSuperNode = true;
sessionStorage.privKey = JSON.stringify(encrypt.createShamirsSecretShares(privKey,10,10));
sessionStorage.selfID = selfID;
alert(`${selfID}\nWelcome ${profiles[selfID].name}`)
initselfWebSocket();
listProfiles();
pingSuperNodeforNewMsgs();
getFollowinglistFromIDB().then(function(result){
following = result;
if(!following.includes(selfID))
following.push(selfID);
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);
});
}).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 = adminID;
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 objectStore0 = event.target.result.createObjectStore("superNodes");
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: 'tweetID' });
objectStore3.createIndex('tid', 'tid', { unique: false });
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");
var objectStore7 = event.target.result.createObjectStore("messages",{ keyPath: 'msgID' });
objectStore7.createIndex('time', 'time', { unique: false });
objectStore7.createIndex('text', 'text', { unique: false });
objectStore7.createIndex('floID', 'floID', { unique: false });
objectStore7.createIndex('type', 'type', { unique: false });
};
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){
var data = JSON.parse(tx.floData).FLO_Tweet_SuperNode;
if(data !== undefined){
storeSuperNodeData(data).then(function (response) {
}).catch(function (error) {
console.log(error.message);
});
}
}else{
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 storeSuperNodeData(data){
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('superNodes', "readwrite").objectStore('superNodes');
if(data.addNodes)
for(var i=0; i<data.addNodes.length; i++)
obs.add(true,data.addNodes[i])
if(data.removeNodes)
for(var i=0; i<data.removeNodes.length; i++)
obs.delete(data.removeNodes[i])
db.close();
resolve('Updated superNodes list in IDB');
};
}
);
}
function getSuperNodeListfromIDB(){
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("superNodes", "readwrite").objectStore("superNodes");
var getReq = obs.getAllKeys();
getReq.onsuccess = function(event){
resolve(event.target.result);
}
getReq.onerror = function(event){
reject('Unable to read superNode list!')
}
db.close();
};
}
);
}
function getuserID(){
return new Promise(
function(resolve,reject){
privKey = (sessionStorage.privKey !== undefined ? encrypt.retrieveShamirSecret(JSON.parse(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 viewHome(){
if( sessionStorage.profiles === undefined || sessionStorage.privKey === undefined || sessionStorage.selfID === undefined || sessionStorage.serverPass === undefined || sessionStorage.superNodeList === undefined ){
alert("Login credentials failed! Returning to login page!");
window.location.href = "index.html";
return;
}
profiles = JSON.parse(sessionStorage.profiles);
console.log(profiles);
privKey = encrypt.retrieveShamirSecret(JSON.parse(sessionStorage.privKey));
selfID = sessionStorage.selfID;
superNodeList = new Set(JSON.parse(sessionStorage.superNodeList));
if(superNodeList.has(selfID)){
modSuperNode = true;
setInterval(reloadInitData, 3600000);
}
kBucketObj.launchKBucket().then(result => {
console.log(result);
initselfWebSocket();
listProfiles();
pingSuperNodeforNewMsgs();
getFollowinglistFromIDB().then(result => {
following = result;
if(!following.includes(selfID))
following.push(selfID);
console.log(following);
displayTweetsFromIDB().then(result => {
connectToAllFollowing();
}).catch(error => {
console.log(error);
})
}).catch(error => {
console.log(error);
})
}).catch(error => {
console.log(error);
});
}
function initselfWebSocket(){
selfWebsocket = new WebSocket("ws://"+location.host+"/ws");
selfWebsocket.onopen = function(evt){
selfWebsocket.onopen = (event) => {
console.log("Connecting");
var pass = (sessionStorage.serverPass !== undefined ? encrypt.retrieveShamirSecret(JSON.parse(sessionStorage.serverPass)): prompt("Enter server password :"));
selfWebsocket.send("$"+pass);
sessionStorage.serverPass = JSON.stringify(encrypt.createShamirsSecretShares(pass,5,5));
var serverPass = encrypt.retrieveShamirSecret(JSON.parse(sessionStorage.serverPass));
selfWebsocket.send("$"+serverPass);
};
selfWebsocket.onclose = function(evt){
selfWebsocket.onclose = (event) => {
console.log("DISCONNECTED");
initselfWebSocket();
};
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 = JSON.stringify(encrypt.createShamirsSecretShares(pass,5,5));
}else if(evt.data == "$Access Granted!")
alert("Access Granted!")
else{
try{
data = JSON.parse(evt.data);
selfWebsocket.onmessage = (event) => {
console.log(event.data);
if(event.data[0] == '$')
return;
try{
data = JSON.parse(event.data);
if(data.follow && encrypt.verify(selfID, data.sign, profiles[data.floID].pubKey)){
var idb = indexedDB.open("FLO_Tweet");
idb.onsuccess = function(event) {
idb.onsuccess = (event) => {
var db = event.target.result;
var obs = db.transaction("followers", "readwrite").objectStore("followers");
obs.add(data.sign,data.floID);
@ -320,7 +68,7 @@ function initselfWebSocket(){
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) {
idb.onsuccess = (event) => {
var db = event.target.result;
var obs = db.transaction("followers", "readwrite").objectStore("followers");
obs.delete(data.floID);
@ -339,44 +87,13 @@ function initselfWebSocket(){
createTweetElement(data.floID,data.time,data.tweet);
}
}else if(modSuperNode){
if(data.reqNewTweets){
kBucketObj.determineClosestSupernode(data.floID).then(result=>{
if(result[0].floID == selfID)
SuperNode_sendTweetsFromIDB(data.floID,data.tid,data.requestor);
}).catch(e => {
console.log(e.message);
});
}else if(data.newSuperNodeTweet){
kBucketObj.determineClosestSupernode(data.floID).then(result=>{
if(result[0].floID == selfID)
SuperNode_storeSuperNodeTweet(data.data,data.tid);
}).catch(e => {
console.log(e.message);
});
}else if(data.viaSuperNodeMsg){
kBucketObj.determineClosestSupernode(data.to).then(result=>{
if(result[0].floID == selfID)
SuperNode_storeViaSuperNodeMsg(data.from,data.to,data.data);
}).catch(e => {
console.log(e.message);
});
}else if(data.viaMsgreq){
kBucketObj.determineClosestSupernode(data.floID).then(result=>{
if(result[0].floID == selfID)
SuperNode_sendviaMsgFromIDB(data.floID);
}).catch(e => {
console.log(e.message);
});
}
superNodeMode(data);
}
}catch(error){
console.log(error.message);
}
}
};
selfWebsocket.onerror = function(evt){
console.log(evt);
}catch(error){
console.log(error);
}
};
selfWebsocket.onerror = (event) => { console.log(event) };
}
function listProfiles(){
@ -394,7 +111,6 @@ function listProfiles(){
</div></a>`
profileList.appendChild(element);
}
//document.getElementById("profileInfo").style.display = "none";
}
function postTweet(){
@ -406,98 +122,40 @@ function postTweet(){
var data = JSON.stringify({floID:selfID,time:time,tweet:tweet,sign:sign});
console.log(data);
selfWebsocket.send(data);
getLastTweetCount(selfID).then(function(result){
sendTweetToSuperNode(data,result+1);
}).catch(function(error){
console.log(error.message);
getLastTweetCount(selfID).then(result => {
var SNdata = JSON.stringify({newSuperNodeTweet:true,floID:selfID,tid:result+1,data:data});
sendDataToSuperNode(selfID,SNdata);
}).catch(error => {
console.log(error);
});
}
function storeTweet(data,tid){
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.tweetID = `${data.time}_${data.floID}`;
data.tid = tid;
obs.add(data);
var obsL = db.transaction("lastTweet", "readwrite").objectStore("lastTweet");
obsL.put(tid,data.floID);
db.close();
};
}
function storeMsg(data){
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("messages", "readwrite").objectStore("messages");
data.msgID = `${data.time}_${data.floID}`;
obs.add(data);
db.close();
};
}
function sendTweetToSuperNode(data,tid){
kBucketObj.determineClosestSupernode(selfID).then(result=>{
var superNodeWS = new WebSocket("ws://"+profiles[result[0].floID].onionAddr+"/ws");
superNodeWS.onopen = function(ev){
console.log(`Connected to self SuperNode!`);
data = JSON.stringify({newSuperNodeTweet:true,floID:selfID,tid:tid,data:data})
console.log(data)
superNodeWS.send(data);
};
superNodeWS.onerror = function(ev) {console.log(`self SuperNode is offline!`);};
superNodeWS.onclose = function(ev) {console.log(`Disconnected from self SuperNode!`);};
}).catch(e => {
console.log(e.message);
});
}
function getFollowinglistFromIDB(){
return new Promise(
function(resolve,reject){
return new Promise((resolve,reject) => {
var idb = indexedDB.open("FLO_Tweet");
idb.onerror = function(event) {
reject("Error in opening IndexedDB!");
};
idb.onsuccess = function(event) {
idb.onerror = (event) => { reject("Error in opening IndexedDB!") };
idb.onsuccess = (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!')
}
getReq.onsuccess = (event) => { resolve(event.target.result) }
getReq.onerror = (event) => { reject('Unable to read following list!') }
db.close();
};
}
);
});
}
function displayTweetsFromIDB(){
return new Promise(
function(resolve,reject){
return new Promise((resolve,reject) => {
var idb = indexedDB.open("FLO_Tweet");
idb.onerror = function(event) {
reject("Error in opening IndexedDB!");
};
idb.onsuccess = function(event) {
idb.onerror = (event) => { reject("Error in opening IndexedDB!") };
idb.onsuccess = (event) => {
var db = event.target.result;
var obs = db.transaction("tweets", "readwrite").objectStore("tweets");
var curReq = obs.openCursor();
curReq.onsuccess = function(event) {
curReq.onsuccess = (event) => {
var cursor = event.target.result;
if(cursor) {
//console.log(cursor.value)
if(cursor.value.floID == selfID || following.includes(cursor.value.floID))
createTweetElement(cursor.value.floID,cursor.value.time,cursor.value.data);
cursor.continue();
@ -505,13 +163,10 @@ function displayTweetsFromIDB(){
resolve("Displayed Tweets from IDB!");
}
}
curReq.onerror = function(event){
reject("Error in Reading tweets from IDB!");
}
curReq.onerror = (event) => { reject("Error in Reading tweets from IDB!") }
db.close();
};
}
);
});
}
function createTweetElement(floID,time,tweet){
@ -539,27 +194,24 @@ function connectToAllFollowing(){
console.log(floid)
followingWebSockets[floid] = new WebSocket("ws://"+profiles[floid].onionAddr+"/ws");
followingWebSockets[floid].onopen = function(ev){
followingWebSockets[floid].onopen = (event) => {
console.log(`Connected to ${floid} Server!`);
getLastTweetCount(floid).then(function(result){
getLastTweetCount(floid).then(result => {
followingWebSockets[floid].send(`>${result}`);
}).catch(function(error){
console.log(error.message);
}).catch(error => {
console.log(error);
});
};
followingWebSockets[floid].onerror = function(ev) {
followingWebSockets[floid].onerror = (event) => {
console.log(`${floid} Server is offline!`);
//Ping SuperNode for any new tweets
pingSuperNodeforNewTweets(floid);
};
followingWebSockets[floid].onclose = function(ev) {
console.log(`Disconnected from ${floid} Server!`);
};
followingWebSockets[floid].onmessage = function(evt){
console.log(evt.data);
followingWebSockets[floid].onclose = (event) => { console.log(`Disconnected from ${floid} Server!`); };
followingWebSockets[floid].onmessage = (event) => {
console.log(event.data);
try{
var data = JSON.parse(evt.data);
var data = JSON.parse(event.data);
var id = data.id;
data = data.data;
if( floid!=data.floID || !encrypt.verify(data.tweet,data.sign,profiles[floid].pubKey))
@ -567,21 +219,20 @@ function connectToAllFollowing(){
storeTweet({floID:data.floID,time:data.time,data:data.tweet},id);
createTweetElement(data.floID,data.time,data.tweet);
}catch(error){
console.log(error.message);
console.log(error);
}
};
});
}
function getLastTweetCount(floid){
return new Promise(
function(resolve,reject){
return new Promise((resolve,reject) => {
var idb = indexedDB.open("FLO_Tweet");
idb.onsuccess = function(event) {
idb.onsuccess = (event) => {
var db = event.target.result;
var lastTweet = db.transaction('lastTweet', "readwrite").objectStore('lastTweet');
var lastTweetReq = lastTweet.get(floid);
lastTweetReq.onsuccess = function(event){
lastTweetReq.onsuccess = (event) => {
var result = event.target.result;
if(result === undefined)
result = 0;
@ -589,8 +240,7 @@ function getLastTweetCount(floid){
}
db.close();
};
}
);
});
}
function pingSuperNodeforNewMsgs(){
@ -599,150 +249,10 @@ function pingSuperNodeforNewMsgs(){
}
function pingSuperNodeforNewTweets(floID){
getLastTweetCount(floID).then(function(result){
getLastTweetCount(floID).then(result => {
var data = JSON.stringify({reqNewTweets:true,floID:floID,tid:result,requestor:selfID})
sendDataToSuperNode(floID,data);
}).catch(function(error){
console.log(error.message);
}).catch(error => {
console.log(error);
});
}
function SuperNode_storeSuperNodeTweet(data,tid){
var idb = indexedDB.open("FLO_Tweet",2);
idb.onerror = function(event) {
console.log("Error in opening IndexedDB!");
};
idb.onupgradeneeded = function(event){
var objectStore1 = event.target.result.createObjectStore("superNodeTweet",{ keyPath: 'tweetID' });
objectStore1.createIndex('floID', 'floID', { unique: false });
objectStore1.createIndex('tid', 'tid', { unique: false });
objectStore1.createIndex('data', 'data', { unique: false });
var objectStore2 = event.target.result.createObjectStore("viaSuperNodeMsg",{ keyPath: 'id',autoIncrement:true });
objectStore2.createIndex('from', 'from', { unique: false });
objectStore2.createIndex('to', 'to', { unique: false });
objectStore2.createIndex('data', 'data', { unique: false });
}
idb.onsuccess = function(event) {
var db = event.target.result;
var obs = db.transaction("superNodeTweet", "readwrite").objectStore("superNodeTweet");
var parsedData = JSON.parse(data);
var tweetID = ''+parsedData.floID+'_'+parsedData.time;
obs.add({tweetID:tweetID,floID:parsedData.floID,tid:tid,data:data});
db.close();
};
}
function SuperNode_storeViaSuperNodeMsg(from,to,data){
var idb = indexedDB.open("FLO_Tweet",2);
idb.onerror = function(event) {
console.log("Error in opening IndexedDB!");
};
idb.onupgradeneeded = function(event){
var objectStore1 = event.target.result.createObjectStore("superNodeTweet",{ keyPath: 'tweetID' });
objectStore1.createIndex('floID', 'floID', { unique: false });
objectStore1.createIndex('tid', 'tid', { unique: false });
objectStore1.createIndex('data', 'data', { unique: false });
var objectStore2 = event.target.result.createObjectStore("viaSuperNodeMsg",{ keyPath: 'id',autoIncrement :true });
objectStore2.createIndex('from', 'from', { unique: false });
objectStore2.createIndex('to', 'to', { unique: false });
objectStore2.createIndex('data', 'data', { unique: false });
}
idb.onsuccess = function(event) {
var db = event.target.result;
var obs = db.transaction("viaSuperNodeMsg", "readwrite").objectStore("viaSuperNodeMsg");
obs.add({from:from,to:to,data:data});
db.close();
};
}
function SuperNode_sendTweetsFromIDB(floID,tid,requestor){
return new Promise(
function(resolve,reject){
var requestorWS = new WebSocket("ws://"+profiles[requestor].onionAddr+"/ws");
requestorWS.onopen = function(ev){
console.log(`sending ${floID} tweets to ${requestor} Server!`);
var idb = indexedDB.open("FLO_Tweet",2);
idb.onerror = function(event) {
reject("Error in opening IndexedDB!");
};
idb.onupgradeneeded = function(event){
var objectStore1 = event.target.result.createObjectStore("superNodeTweet",{ keyPath: 'tweetID' });
objectStore1.createIndex('floID', 'floID', { unique: false });
objectStore1.createIndex('tid', 'tid', { unique: false });
objectStore1.createIndex('data', 'data', { unique: false });
var objectStore2 = event.target.result.createObjectStore("viaSuperNodeMsg",{ keyPath: 'id',autoIncrement:true });
objectStore2.createIndex('from', 'from', { unique: false });
objectStore2.createIndex('to', 'to', { unique: false });
objectStore2.createIndex('data', 'data', { unique: false });
}
idb.onsuccess = function(event) {
var db = event.target.result;
var obs = db.transaction("superNodeTweet", "readwrite").objectStore("superNodeTweet");
var curReq = obs.openCursor();
curReq.onsuccess = function(event) {
var cursor = event.target.result;
if(cursor) {
if(cursor.value.floID == floID && cursor.value.tid > tid){
data = JSON.stringify({fromSuperNode:true, floID:cursor.value.floID,tid:cursor.value.tid,data:cursor.value.data})
requestorWS.send(data);
}
cursor.continue();
}else{
resolve("Displayed Tweets from IDB!");
}
}
curReq.onerror = function(event){
reject("Error in Reading tweets from IDB!");
}
db.close();
};
};
requestorWS.onerror = function(ev) {
console.log(`${requestor} Server is offline!`);
};
requestorWS.onclose = function(ev) {
console.log(`Disconnected from ${requestor} Server!`);
};
}
);
}
function SuperNode_sendviaMsgFromIDB(floID){
var receiverWS = new WebSocket("ws://"+profiles[floID].onionAddr+"/ws");
receiverWS.onopen = function(ev){
var idb = indexedDB.open("FLO_Tweet",2);
idb.onerror = function(event) {
console.log("Error in opening IndexedDB!");
};
idb.onupgradeneeded = function(event) {
var objectStore1 = event.target.result.createObjectStore("superNodeTweet",{ keyPath: 'tweetID' });
objectStore1.createIndex('floID', 'floID', { unique: false });
objectStore1.createIndex('tid', 'tid', { unique: false });
objectStore1.createIndex('data', 'data', { unique: false });
var objectStore2 = event.target.result.createObjectStore("viaSuperNodeMsg",{ keyPath: 'id',autoIncrement:true });
objectStore2.createIndex('from', 'from', { unique: false });
objectStore2.createIndex('to', 'to', { unique: false });
objectStore2.createIndex('data', 'data', { unique: false });
};
idb.onsuccess = function(event) {
var db = event.target.result;
var obs = db.transaction("viaSuperNodeMsg", "readwrite").objectStore("viaSuperNodeMsg");
obs.openCursor().onsuccess = function(event) {
var cursor = event.target.result;
if(cursor) {
if(cursor.value.to == floID){
receiverWS.send(cursor.value.data);
cursor.delete();
}
cursor.continue();
}else{
console.log('Sent All messages to '+floID)
}
}
db.close();
};
};
receiverWS.onerror = function(ev) { console.log('Connection Error to '+floID) };
receiverWS.onclose = function(ev) { console.log('Disconnected from '+floID) };
}

View File

@ -1,5 +1,146 @@
<html>
<script type="text/javascript">
window.location.href = "home.html";
</script>
<head>
<title>Login</title>
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css">
<style>
@charset "utf-8";
/* CSS Document */
h1{
margin: 0 auto;
padding-left: 15%;
text-transform:uppercase;
font-size:30px;
color:white;
}
h2{
margin: 0 auto;
padding-left: 15%;
font-size:18px;
color:#fff;
}
body {
font-family: Helvetica;
margin:0 auto;
min-height:100%;
background: lightblue;
-webkit-background-size: cover;
-moz-background-size: cover;
-o-background-size: cover;
background-size: cover;
}
.nav {
margin: 0 auto;
margin-top: 100px;
margin-left: 35%;
width: 300px;
height: auto;
background: #fff;
border-radius: 5px;
text-align: center;
padding-top: 10px;
padding-bottom: 10px;
box-shadow: 0 0 10px rgba(0,0,0, .5);
}
.input {
border: 1px solid #a6a6a6;
width: 230px;
height: 40px;
border-radius: 3px;
margin-top: 5px;
padding-left: 9px;
color: #6c6c6c;
background: #fcfcfc;
outline: none;
}
.input:hover:enabled{
box-shadow: 0 0 10px #337AB7;
border: 1px #337AB7 solid ;
}
.input:focus, .button:focus, .button:hover:focus{
box-shadow: 0 0 10px #337AB7;
border: 1px #337AB7 solid ;
}
.button {
color:#fff;
font-size:20px;
border: 1px solid #a6a6a6;
width: 243px;
height: 43px;
border-radius: 5px;
margin-top: 5px;
margin-right: 6px;
outline: none;
}
.button:disabled,.input:disabled{
cursor:not-allowed;
}
label {
position: relative;
top: 5px;
margin-right: 115px;
}
label span {
margin-left: 5px;
font-size:14px;
}
</style>
<style>
#alert-container{
width: 100%;
text-align: center;
position: fixed;
top:0;
z-index: 2;
}
.alert {
padding: 10px;
color: white;
max-width: 700px;
margin: 0 auto;
}
.closebtn {
margin-left: 15px;
color: white;
font-weight: bold;
float: right;
cursor: pointer;
transition: 0.3s;
}
.closebtn:hover {
color: black;
}
</style>
<script type="text/javascript" src="init.js"></script>
<script type="text/javascript" src="app.js"></script>
<script type="text/javascript" src="login.js"></script>
</head>
<body onload="initAPIdata();">
<div id="alert-container"></div>
<div class="nav">
<form id='serverConnect'>
<input type="password" id="serverPass" class="input" placeholder="ServerPass" />
<input type="button" value="Connect" class="button btn-primary" onclick="connect()"/></br>
</form>
<form id='userSignIn'>
<input type="text" id="username" class="input" placeholder="Username" disabled/>
<input type="password" id="privKey" class="input" placeholder="PrivKey" disabled/>
<input type="button" value="Sign In" class="button btn-primary" onclick="signIn()" disabled/>
</form>
</div>
</body>
</html>

13418
app/web/registerID.js → app/web/init.js vendored Executable file → Normal file

File diff suppressed because it is too large Load Diff

334
app/web/login.js Normal file
View File

@ -0,0 +1,334 @@
if( sessionStorage.profiles && sessionStorage.privKey && sessionStorage.selfID && sessionStorage.serverPass && sessionStorage.superNodeList ){
window.location.replace("home.html");
}
const sendAmt = 0.001 ;
const fee = 0.0005;
var username,privKey,floID;
var profiles;
function initAPIdata(){
return new Promise((resolve,reject) => {
console.log("initAPIdata");
getDatafromAPI().then(result => {
console.log(result);
getProfilesfromIDB().then(result => {
profiles = arrayToObject(result);
console.log(profiles);
sessionStorage.profiles = JSON.stringify(profiles);
getSuperNodeListfromIDB().then(result => {
console.log(result)
superNodeList = new Set(result);
sessionStorage.superNodeList = JSON.stringify(Array.from(superNodeList));
resolve('Refresh API data Successful!')
}).catch(error => {
reject(error);
});
}).catch(error => {
reject(error);
});
}).catch(error => {
reject(error);
});
});
}
function customAlert(msg,type){
color = {info:"#2196F3",danger:"#f44336",warning:"#ff9800",success:"#4CAF50"};
var alertBox = document.createElement('div');
alertBox.setAttribute('class','alert');
alertBox.style.backgroundColor = color[type];
alertBox.innerHTML = `<span class="closebtn" onclick="this.parentElement.style.display='none';">&#10006;</span>
${msg}`;
document.getElementById("alert-container").appendChild(alertBox);
}
function disableForm(formId, disableFlag) {
var form = document.getElementById(formId);
for(var i=0; i<form.length; i++)
form[i].disabled = disableFlag;
}
function connect(){
document.getElementById("alert-container").innerHTML = '';
var serverPass = document.getElementById('serverPass').value;
initselfWebSocket(serverPass).then(result => {
sessionStorage.serverPass = JSON.stringify(encrypt.createShamirsSecretShares(serverPass,10,10));
customAlert(result,'success');
disableForm('serverConnect',true);
disableForm('userSignIn',false);
}).catch(error => {
customAlert(error,'danger');
});
}
function signIn(){
document.getElementById("alert-container").innerHTML = '';
username = document.getElementById('username').value;
privKey = document.getElementById('privKey').value;
var key = new Bitcoin.ECKey(privKey);
if(key.priv == null){
customAlert("Invalid FLO Private Key!",'danger');
return false;
}
key.setCompressed(true);
floID = key.getBitcoinAddress();
try{
console.log(floID)
if (profiles[floID] === undefined)
throw `${floID} is not registers to FLO Tweet!<br/>Register FLO ID to this onion?`;
if (profiles[floID].onionAddr != window.location.host)
throw `${floID} is registered to another onion!<br/>Change to this onion?`;
if (profiles[floID].name != username)
throw `${floID} is registered to another username!<br/>Change username?`;
login();
}catch(msg){
console.log(msg)
customAlert(`${msg}<span class="closebtn" onclick="this.parentElement.parentElement.style.display='none'; signUp();">&#10004;</span>`,'warning');
}
}
function login(){
sessionStorage.privKey = JSON.stringify(encrypt.createShamirsSecretShares(privKey,10,10));
sessionStorage.selfID = floID;
disableForm('userSignIn',true);
customAlert(`Welcome ${username}`,'info');
setTimeout(window.location.replace("home.html"), 3000);
}
function signUp(){
registerID(floID,window.location.host,privKey,privKey.getPubKeyHex(),username).then(result =>{
customAlert(`Registration Successful!<br/> txid : ${result}`,'success');
refreshAPIdata().then(result => {
console.log(result);
login();
}).catch(error => {
console.log(error);
});
}).catch(error => {
customAlert(error,'danger');
});
}
function ajax(method, uri){
var request = new XMLHttpRequest();
var url = `${api_url}/${uri}`
console.log(url)
var result;
request.open(method,url , false);
request.onload = function () {
if (request.readyState == 4 && request.status == 200)
result = this.response;
else {
console.log('error');
result = false;
}
};
request.send();
console.log(result);
return result;
}
function getDatafromAPI(){
return new Promise((resolve,reject) => {
var addr = adminID;
var idb = indexedDB.open("FLO_Tweet");
idb.onerror = (event) => { reject("Error in opening IndexedDB!") };
idb.onupgradeneeded = (event) => {
var db = event.target.result;
var objectStore0 = event.target.result.createObjectStore("superNodes");
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: 'tweetID' });
objectStore3.createIndex('tid', 'tid', { unique: false });
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");
var objectStore7 = event.target.result.createObjectStore("messages",{ keyPath: 'msgID' });
objectStore7.createIndex('time', 'time', { unique: false });
objectStore7.createIndex('text', 'text', { unique: false });
objectStore7.createIndex('floID', 'floID', { unique: false });
objectStore7.createIndex('type', 'type', { unique: false });
};
idb.onsuccess = (event) => {
var db = event.target.result;
var lastTx = db.transaction('lastTx', "readwrite").objectStore('lastTx');
console.log(addr);
new Promise((res,rej) => {
var lastTxReq = lastTx.get(addr);
lastTxReq.onsuccess = (event) => {
var lasttx = event.target.result;
if(lasttx === undefined){
lasttx = 0;
}
res(lasttx);
}
}).then(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(tx => {
try {
if (tx.vin[0].addr == addr){
var data = JSON.parse(tx.floData).FLO_Tweet_SuperNode;
if(data !== undefined){
storeSuperNodeData(data).then(function (response) {
}).catch(error => {
console.log(error);
});
}
}else{
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};
storeProfile(data).then(function (response) {
}).catch(error => {
console.log(error);
});
}
}
} catch (error) {
//console.log(error)
}
});
var obs = db.transaction('lastTx', "readwrite").objectStore('lastTx');
obs.put(response.totalItems,addr);
break;
}
db.close();
resolve('retrived data from API');
});
};
});
}
function getProfilesfromIDB(){
return new Promise((resolve,reject) => {
var idb = indexedDB.open("FLO_Tweet");
idb.onerror = (event) => { reject("Error in opening IndexedDB!") };
idb.onsuccess = (event) => {
var db = event.target.result;
var obs = db.transaction("profiles", "readwrite").objectStore("profiles");
var getReq = obs.getAll();
getReq.onsuccess = (event) => { resolve(event.target.result) }
getReq.onerror = (event) => { reject('Unable to read profiles!') }
db.close();
};
});
}
function getSuperNodeListfromIDB(){
return new Promise((resolve,reject) => {
var idb = indexedDB.open("FLO_Tweet");
idb.onerror = (event) => { reject("Error in opening IndexedDB!") };
idb.onsuccess = (event) => {
var db = event.target.result;
var obs = db.transaction("superNodes", "readwrite").objectStore("superNodes");
var getReq = obs.getAllKeys();
getReq.onsuccess = (event) => { resolve(event.target.result) }
getReq.onerror = (event) => { reject('Unable to read superNode list!') }
db.close();
};
});
}
function initselfWebSocket(serverPass){
return new Promise((resolve,reject) => {
selfWebsocket = new WebSocket("ws://"+location.host+"/ws");
selfWebsocket.onopen = (event) => {
console.log("Connecting");
selfWebsocket.send("$"+serverPass);
};
selfWebsocket.onclose = (event) => { console.log("DISCONNECTED") };
selfWebsocket.onmessage = (event) => {
console.log(event.data);
if(event.data == "$Access Denied!")
reject("Access Denied!");
else if(event.data == "$Access Granted!")
resolve("Access Granted!");
};
selfWebsocket.onerror = (event) => { console.log(event) };
});
}
function registerID(sender,onionAddr,wif,pubkey,username) {
return new Promise((resolve,reject) => {
var trx = bitjs.transaction();
var utxoAmt = 0.0;
var x = sendAmt+fee;
var response = ajax("GET",`api/addr/${sender}/utxo`);
var utxos = JSON.parse(response);
for(var x = utxos.length-1; x >= 0; x--){
if(utxoAmt < sendAmt+fee){
trx.addinput(utxos[x].txid, utxos[x].vout, utxos[x].scriptPubKey);
utxoAmt += utxos[x].amount;
}else
break;
}
console.log(utxoAmt+":"+(sendAmt+fee));
if(utxoAmt < sendAmt+fee)
reject("Insufficient balance!");
trx.addoutput(adminID, sendAmt);
console.log(adminID+":"+ sendAmt);
var change = utxoAmt-sendAmt-fee;
if(change>0)
trx.addoutput(sender, change);
console.log(sender+":"+ change);
var key = new Bitcoin.ECKey(wif);
var sendFloData = JSON.stringify({FLO_Tweet:{onionAddr:onionAddr, name: username, pubKey: pubkey}});;
trx.addflodata(sendFloData);
console.log(sendFloData);
var signedTxHash = trx.sign(wif, 1);
console.log(signedTxHash);
var txid = broadcastTx(signedTxHash);
if (txid)
resolve(txid);
else
reject('Registration Unsuccessful!')
});
}
function broadcastTx(signedTxHash) {
var http = new XMLHttpRequest();
var url = `${api_url}/api/tx/send`;
if (signedTxHash.length < 1) {
return false;
}
var params = `{"rawtx":"${signedTxHash}"}`;
var result;
http.open('POST', url, false);
//Send the proper header information along with the request
http.setRequestHeader('Content-type', 'application/json');
http.onreadystatechange = function () { //Call a function when the state changes.
if (http.readyState == 4 && http.status == 200) {
console.log(http.response);
var txid = JSON.parse(http.response).txid.result;
console.log("Transaction successful! txid : " + txid);
result = txid;
} else {
console.log(http.responseText);
result = false;
}
}
http.send(params);
return result;
}

View File

@ -9,7 +9,7 @@
<!-- Font Awesome File -->
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/4.7.0/css/font-awesome.min.css">
<script type="text/javascript" src="registerID.js"></script>
<script type="text/javascript" src="init.js"></script>
<script type="text/javascript" src="app.js"></script>
<script type="text/javascript" src="msg.js"></script>

View File

@ -1,33 +1,37 @@
var profiles;
var receiverID,selfID,privKey;
var receiverID,selfID,privKey,modSuperNode;
var selfwebsocket,receiverWebSocket,recStat;
function initMsgs(){
if( sessionStorage.profiles === undefined || sessionStorage.privKey === undefined || sessionStorage.selfID === undefined || sessionStorage.serverPass === undefined){
alert("Login credentials failed! Returning to home page!");
window.location.href = "home.html";
if( sessionStorage.profiles === undefined || sessionStorage.privKey === undefined || sessionStorage.selfID === undefined || sessionStorage.serverPass === undefined || sessionStorage.superNodeList === undefined ){
alert("Login credentials failed! Returning to login page!");
window.location.href = "index.html";
return;
}
profiles = JSON.parse(sessionStorage.profiles);
console.log(profiles);
privKey = encrypt.retrieveShamirSecret(JSON.parse(sessionStorage.privKey));
selfID = sessionStorage.selfID;
superNodeList = JSON.parse(sessionStorage.superNodeList);
kBucketObj.launchKBucket().then(function(result){
superNodeList = new Set(JSON.parse(sessionStorage.superNodeList));
if(superNodeList.has(selfID)){
modSuperNode = true;
setInterval(reloadInitData, 3600000);
}
kBucketObj.launchKBucket().then(result => {
console.log(result)
initselfWebSocket();
readMsgfromIDB().then(function(result){
readMsgfromIDB().then(result => {
listProfiles();
document.getElementById("sendMsgInput").addEventListener("keyup",function(event){
document.getElementById("sendMsgInput").addEventListener("keyup",(event) => {
if(event.keyCode === 13){
event.preventDefault();
sendMsg();
}
});
}).catch(function(error){
}).catch(error => {
console.log(error);
});
}).catch(function(error){
}).catch(error => {
console.log(error);
});
}
@ -42,32 +46,33 @@ function listProfiles(){
var element = document.createElement("div");
element.setAttribute("class", "media");
element.innerHTML = `<a href="javascript:changeReceiver('${p}');"><div class="media-body">
<h5 class="media-heading">${profiles[p].name}</h5>
<small>@${p}</small>
</div></a>`
<h5 class="media-heading">${profiles[p].name}</h5>
<small>@${p}</small>
</div></a>`
profileList.appendChild(element);
}
}
function initselfWebSocket(){
selfWebsocket = new WebSocket("ws://"+location.host+"/ws");
selfWebsocket.onopen = function(evt){
selfWebsocket.onopen = (event) => {
console.log("Connecting");
var serverPass = encrypt.retrieveShamirSecret(JSON.parse(sessionStorage.serverPass));
selfWebsocket.send("$"+serverPass);
};
selfWebsocket.onclose = function(evt){
selfWebsocket.onclose = (event) => {
console.log("DISCONNECTED");
initselfWebSocket();
};
selfWebsocket.onmessage = function(evt){
console.log(evt.data);
if(evt.data[0] == '$')
selfWebsocket.onmessage = (event) => {
console.log(event.data);
if(event.data[0] == '$')
return;
try{
data = JSON.parse(evt.data);
data = JSON.parse(event.data);
if(data.follow && encrypt.verify(selfID, data.sign, profiles[data.floID].pubKey)){
var idb = indexedDB.open("FLO_Tweet");
idb.onsuccess = function(event) {
idb.onsuccess = (event) => {
var db = event.target.result;
var obs = db.transaction("followers", "readwrite").objectStore("followers");
obs.add(data.sign,data.floID);
@ -76,7 +81,7 @@ function initselfWebSocket(){
selfWebsocket.send(`F${data.floID}-${data.sign}`);
}else if(data.unfollow && encrypt.verify(selfID, data.sign, profiles[data.floID].pubKey)){
var idb = indexedDB.open("FLO_Tweet");
idb.onsuccess = function(event) {
idb.onsuccess = (event) => {
var db = event.target.result;
var obs = db.transaction("followers", "readwrite").objectStore("followers");
obs.delete(data.floID);
@ -89,19 +94,18 @@ function initselfWebSocket(){
createMsgElement(data.from,data.time,msg,'R')
storeMsg({time:data.time,floID:data.from,text:msg,type:'R'});
}
}else if(modSuperNode){
superNodeMode(data);
}
}catch(error){
console.log(error.message)
console.log(error)
}
};
selfWebsocket.onerror = function(evt){
console.log(evt);
};
selfWebsocket.onerror = (event) => { console.log(event) };
}
function readMsgfromIDB(){
return new Promise(
function(resolve,reject){
return new Promise((resolve,reject) => {
var disp = document.getElementById("msgsContainer");
for(floID in profiles){
var element = document.createElement('div');
@ -110,13 +114,11 @@ function readMsgfromIDB(){
disp.appendChild(element);
}
var idb = indexedDB.open("FLO_Tweet");
idb.onerror = function(event) {
reject("Error in opening IndexedDB!");
};
idb.onsuccess = function(event) {
idb.onerror = (event) => { reject("Error in opening IndexedDB!") };
idb.onsuccess = (event) => {
var db = event.target.result;
var obs = db.transaction("messages", "readwrite").objectStore("messages");
obs.openCursor().onsuccess = function(event) {
obs.openCursor().onsuccess = (event) => {
var cursor = event.target.result;
if(cursor) {
createMsgElement(cursor.value.floID,cursor.value.time,cursor.value.text,cursor.value.type);
@ -128,8 +130,7 @@ function readMsgfromIDB(){
};
db.close();
};
}
);
});
}
function changeReceiver(floID){
@ -148,9 +149,9 @@ function changeReceiver(floID){
document.getElementById(receiverID).style.display = 'block';
try{
receiverWebSocket = new WebSocket("ws://"+profiles[receiverID].onionAddr+"/ws");
receiverWebSocket.onopen = function(ev){ recStat = true; };
receiverWebSocket.onerror = function(ev) { recStat = false;};
receiverWebSocket.onclose = function(ev) { recStat = false; };
receiverWebSocket.onopen = (event) => { recStat = true; };
receiverWebSocket.onerror = (event) => { recStat = false;};
receiverWebSocket.onclose = (event) => { recStat = false; };
}catch(e){
console.log(e);
}
@ -161,23 +162,22 @@ function sendMsg(){
alert("Select a contact and send message");
return;
}
var inp = document.getElementById('sendMsgInput')
var msg = inp.value
inp.value = ""
console.log(msg)
var time = Date.now()
var sign = encrypt.sign(msg,privKey)
var msgEncrypt = encrypt.encryptMessage(msg,profiles[receiverID].pubKey)
var inp = document.getElementById('sendMsgInput');
var msg = inp.value;
inp.value = "";
console.log(msg);
var time = Date.now();
var sign = encrypt.sign(msg,privKey);
var msgEncrypt = encrypt.encryptMessage(msg,profiles[receiverID].pubKey);
var data = JSON.stringify({message:true,from:selfID,to:receiverID,time:time,secret:msgEncrypt.secret,sign:sign,pubVal:msgEncrypt.senderPublicKeyString});
if(recStat)
receiverWebSocket.send(data);
else{
var SNdata = JSON.stringify({viaSuperNodeMsg:true,from:selfID,to:receiverID,data:data})
sendDataToSuperNode(receiverID,SNdata)
var SNdata = JSON.stringify({viaSuperNodeMsg:true,from:selfID,to:receiverID,data:data});
sendDataToSuperNode(receiverID,SNdata);
}
console.log(`sentMsg : ${data}`);
createMsgElement(receiverID,time,msg,'S')
createMsgElement(receiverID,time,msg,'S');
storeMsg({time:time,floID:receiverID,text:msg,type:'S'});
}
@ -194,17 +194,3 @@ function createMsgElement(floID,time,msg,type){
</div>`;
msgField.appendChild(element);
}
function storeMsg(data){
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("messages", "readwrite").objectStore("messages");
data.msgID = `${data.time}_${data.floID}`;
obs.add(data);
db.close();
};
}

View File

@ -8,7 +8,7 @@
<link rel="stylesheet" href="styles.css">
<!-- Font Awesome File -->
<script type="text/javascript" src="registerID.js"></script>
<script type="text/javascript" src="init.js"></script>
<script type="text/javascript" src="app.js"></script>
<script type="text/javascript" src="profile.js"></script>

View File

@ -1,12 +1,12 @@
var profileWebsocket, selfWebsocket,profileServerStatus;
var profiles;
var profileID, privKey, selfID;
var profileID, privKey, selfID, modSuperNode;
function viewProfile(){
if( sessionStorage.profiles === undefined || sessionStorage.privKey === undefined || sessionStorage.selfID === undefined || sessionStorage.serverPass === undefined){
alert("Login credentials failed! Returning to home page!");
window.location.href = "home.html";
if( sessionStorage.profiles === undefined || sessionStorage.privKey === undefined || sessionStorage.selfID === undefined || sessionStorage.serverPass === undefined || sessionStorage.superNodeList === undefined ){
alert("Login credentials failed! Returning to login page!");
window.location.href = "index.html";
return;
}
profiles = JSON.parse(sessionStorage.profiles);
@ -15,13 +15,17 @@ function viewProfile(){
selfID = sessionStorage.selfID;
var url = new URL(window.location.href);
profileID = url.searchParams.get("floID");
superNodeList = JSON.parse(sessionStorage.superNodeList);
kBucketObj.launchKBucket().then(function(result){
superNodeList = new Set(JSON.parse(sessionStorage.superNodeList));
if(superNodeList.has(selfID)){
modSuperNode = true;
setInterval(reloadInitData, 3600000);
}
kBucketObj.launchKBucket().then(result => {
console.log(result)
listProfiles();
displayProfile(profileID);
}).catch(function(error){
console.log(error.message);
}).catch(error => {
console.log(error);
});
}
@ -30,7 +34,7 @@ function displayProfile(profileID){
var errorMsg;
if(!profileID)
errorMsg = "Select a Profile to display";
else if(!validateAddr(profileID))
else if(!encrypt.validateAddr(profileID))
errorMsg = "Invalid FLO ID";
else if(!(profileID in profiles))
errorMsg = "FLO ID not registered to FLO Tweet";
@ -44,32 +48,29 @@ function displayProfile(profileID){
document.getElementById("profileName").innerHTML=profiles[profileID].name;
document.getElementById("profileFloID").innerHTML='@'+profileID;
initselfWebSocket();
displayTweetFromIDB(profileID).then(function(result){
connectToX(profileID).then(function(result){
displayTweetFromIDB(profileID).then(result => {
connectToProfileServer(profileID).then(result => {
console.log(result);
profileServerStatus = true;
getTweetsFromX(profileID);
}).catch(function(error){
pingProfileServerforNewTweets(profileID);
}).catch(error => {
console.log(error);
pingSuperNodeforNewTweets(profileID);
profileServerStatus = false;
});
}).catch(function(error){
console.log(error.message);
}).catch(error => {
console.log(error);
});
}
function displayTweetFromIDB(floID){
return new Promise(
function(resolve,reject){
return new Promise((resolve,reject) => {
var idb = indexedDB.open("FLO_Tweet");
idb.onerror = function(event) {
reject("Error in opening IndexedDB!");
};
idb.onsuccess = function(event) {
idb.onerror = (event) => { reject("Error in opening IndexedDB!") };
idb.onsuccess = (event) => {
var db = event.target.result;
var obj = db.transaction("following", "readwrite").objectStore("following");
obj.get(floID).onsuccess = function (event) {
obj.get(floID).onsuccess = (event) => {
var followBtn = document.getElementById("follow-button");
if(event.target.result === undefined){
followBtn.innerHTML = "+ Follow";
@ -81,7 +82,7 @@ function displayTweetFromIDB(floID){
followBtn.disabled = false;
}
var obs = db.transaction("tweets", "readwrite").objectStore("tweets");
obs.openCursor().onsuccess = function(event) {
obs.openCursor().onsuccess = (event) => {
var cursor = event.target.result;
if(cursor) {
//console.log(cursor.value)
@ -94,8 +95,7 @@ function displayTweetFromIDB(floID){
}
db.close();
};
}
);
});
}
function listProfiles(){
@ -111,7 +111,6 @@ function listProfiles(){
</div></a>`
profileList.appendChild(element);
}
//document.getElementById("profileInfo").style.display = "none";
}
function createTweetElement(floID,time,tweet){
@ -133,23 +132,16 @@ function createTweetElement(floID,time,tweet){
tweetDisplay.insertBefore(element, tweetDisplay.firstChild);
}
function connectToX(floID){
return new Promise(
function(resolve,reject){
function connectToProfileServer(floID){
return new Promise((resolve,reject) => {
profileWebsocket = new WebSocket("ws://"+profiles[floID].onionAddr+"/ws");
profileWebsocket.onopen = function(ev){
resolve("Connected to Profile Server!");
};
profileWebsocket.onerror = function(ev) {
reject("Profile Server is offline!");
};
profileWebsocket.onclose = function(ev) {
console.log("Disconnected from Profile Server!")
};
profileWebsocket.onmessage = function(evt){
console.log(evt.data);
profileWebsocket.onopen = (event) => { resolve("Connected to Profile Server!") };
profileWebsocket.onerror = (event) => { reject("Profile Server is offline!") };
profileWebsocket.onclose = (event) => { console.log("Disconnected from Profile Server!") };
profileWebsocket.onmessage = (event) => {
console.log(event.data);
try{
var data = JSON.parse(evt.data);
var data = JSON.parse(event.data);
var id = data.id;
data = data.data;
if( floID!=data.floID || !encrypt.verify(data.tweet,data.sign,profiles[floID].pubKey))
@ -157,76 +149,41 @@ function connectToX(floID){
storeTweet({floID:floID,time:data.time,data:data.tweet},id);
createTweetElement(floID,data.time,data.tweet);
}catch(error){
console.log(error.message);
console.log(error);
}
}
}
);
}
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.tweetID = `${data.time}_${data.floID}`;
obs.add(data);
var obsL = db.transaction("lastTweet", "readwrite").objectStore("lastTweet");
obsL.put(id,data.floID);
db.close();
};
}
function storeMsg(data){
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("messages", "readwrite").objectStore("messages");
data.msgID = `${data.time}_${data.floID}`;
obs.add(data);
db.close();
};
});
}
function pingSuperNodeforNewTweets(floID){
getLastTweetCount(floID).then(function(result){
var data = JSON.stringify({reqNewTweets:true,floID:floID,tid:result,requestor:selfID})
sendDataToSuperNode(floID,data);
}).catch(function(error){
console.log(error.message);
});
getLastTweetCount(floID).then(result => {
var data = JSON.stringify({reqNewTweets:true,floID:floID,tid:result,requestor:selfID})
sendDataToSuperNode(floID,data);
}).catch(error => {
console.log(error);
});
}
function getTweetsFromX(floID){
return new Promise(
function (resolve,reject){
getLastTweetCount(floID).then(function(result){
console.log(profileWebsocket);
profileWebsocket.send(`>${result}`);
console.log("sent");
resolve('Sent New tweet request to user server!');
}).catch(function(error){
console.log(error.message);
});
}
);
function pingProfileServerforNewTweets(floID){
getLastTweetCount(floID).then(result => {
console.log(profileWebsocket);
profileWebsocket.send(`>${result}`);
console.log("Sent New tweet request to user server!");
//resolve('Sent New tweet request to user server!');
}).catch(error => {
console.log(error);
});
}
function getLastTweetCount(floid){
return new Promise(
function(resolve,reject){
return new Promise((resolve,reject) => {
var idb = indexedDB.open("FLO_Tweet");
idb.onsuccess = function(event) {
idb.onerror = (event) => { reject("Error in opening IndexedDB!") };
idb.onsuccess = (event) => {
var db = event.target.result;
var lastTweet = db.transaction('lastTweet', "readwrite").objectStore('lastTweet');
var lastTweetReq = lastTweet.get(floid);
lastTweetReq.onsuccess = function(event){
lastTweetReq.onsuccess = (event) => {
var result = event.target.result;
if(result === undefined)
result = 0;
@ -234,29 +191,29 @@ function getLastTweetCount(floid){
}
db.close();
};
}
);
});
}
function initselfWebSocket(){
selfWebsocket = new WebSocket("ws://"+location.host+"/ws");
selfWebsocket.onopen = function(evt){
selfWebsocket.onopen = (event) => {
console.log("Connecting");
var serverPass = encrypt.retrieveShamirSecret(JSON.parse(sessionStorage.serverPass));
selfWebsocket.send("$"+serverPass);
};
selfWebsocket.onclose = function(evt){
selfWebsocket.onclose = (event) => {
console.log("DISCONNECTED");
initselfWebSocket();
};
selfWebsocket.onmessage = function(evt){
console.log(evt.data);
if(evt.data[0] == '$')
selfWebsocket.onmessage = (event) => {
console.log(event.data);
if(event.data[0] == '$')
return;
try{
data = JSON.parse(evt.data);
data = JSON.parse(event.data);
if(data.follow && encrypt.verify(selfID, data.sign, profiles[data.floID].pubKey)){
var idb = indexedDB.open("FLO_Tweet");
idb.onsuccess = function(event) {
idb.onsuccess = (event) => {
var db = event.target.result;
var obs = db.transaction("followers", "readwrite").objectStore("followers");
obs.add(data.sign,data.floID);
@ -265,7 +222,7 @@ function initselfWebSocket(){
selfWebsocket.send(`F${data.floID}-${data.sign}`);
}else if(data.unfollow && encrypt.verify(selfID, data.sign, profiles[data.floID].pubKey)){
var idb = indexedDB.open("FLO_Tweet");
idb.onsuccess = function(event) {
idb.onsuccess = (event) => {
var db = event.target.result;
var obs = db.transaction("followers", "readwrite").objectStore("followers");
obs.delete(data.floID);
@ -283,14 +240,14 @@ function initselfWebSocket(){
storeTweet({floID:data.floID,time:data.time,data:data.tweet},tid);
createTweetElement(data.floID,data.time,data.tweet);
}
}else if(modSuperNode){
superNodeMode(data);
}
}catch(error){
console.log(error.message)
console.log(error)
}
};
selfWebsocket.onerror = function(evt){
console.log(evt);
};
selfWebsocket.onerror = (event) => { console.log(event) };
}
function follow(){
@ -301,12 +258,12 @@ function follow(){
if(profileServerStatus)
profileWebsocket.send(data);
else{
var SNdata = JSON.stringify({viaSuperNodeMsg:true,from:selfID,to:profileID,data:data})
sendDataToSuperNode(profileID,SNdata)
var SNdata = JSON.stringify({viaSuperNodeMsg:true,from:selfID,to:profileID,data:data});
sendDataToSuperNode(profileID,SNdata);
}
selfWebsocket.send(`f${profileID}-${sign}`)
var idb = indexedDB.open("FLO_Tweet");
idb.onsuccess = function(event) {
idb.onsuccess = (event) => {
var db = event.target.result;
var obs = db.transaction("following", "readwrite").objectStore("following");
obs.add(sign,profileID);
@ -321,12 +278,12 @@ function follow(){
if(profileServerStatus)
profileWebsocket.send(data);
else{
var SNdata = JSON.stringify({viaSuperNodeMsg:true,from:selfID,to:profileID,data:data})
sendDataToSuperNode(profileID,SNdata)
var SNdata = JSON.stringify({viaSuperNodeMsg:true,from:selfID,to:profileID,data:data});
sendDataToSuperNode(profileID,SNdata);
}
selfWebsocket.send(`u${profileID}`)
var idb = indexedDB.open("FLO_Tweet");
idb.onsuccess = function(event) {
idb.onsuccess = (event) => {
var db = event.target.result;
var obs = db.transaction("following", "readwrite").objectStore("following");
obs.delete(profileID);
@ -336,4 +293,3 @@ function follow(){
followBtn.innerHTML = "+ Follow";
}
}