FLO_Twitter/app/web/login.js
sairajzero 174b9fddf6 Improved user login and stability of funtions
Old prompt based user login and server connect are replaced with login page
Improved stability and simplification of functions
Moved all superNode functions to app.js
Supernode mode will now work in all pages (home,profile,msg) instead of just home
2019-07-24 03:01:29 +05:30

380 lines
15 KiB
JavaScript

if( sessionStorage.profiles && sessionStorage.privKey && sessionStorage.selfID && sessionStorage.serverPass && sessionStorage.superNodeList ){
window.location.replace("home.html");
return;
}
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/`;
const sendAmt = 0.001 ;
const fee = 0.0005;
var username,privKey,floID;
var profiles;
function refreshAPIdata(){
return new Promise((resolve,reject) => {
console.log("refreshAPIdata");
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 = result;
sessionStorage.superNodeList = JSON.stringify(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');
initselfWebSocket(serverPass).then(result => {
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');
}
}
async function login(){
sessionStorage.privKey = JSON.stringify(encrypt.createShamirsSecretShares(privKey,10,10));
sessionStorage.selfID = floID;
customAlert(`Welcome ${username}`,'info');
await sleep(3000);
window.location.replace("home.html");
}
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 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 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) };
});
}
//Script for AJAX, and register functions
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;
}