Bug fixes

- Converted messenger to IIF
- Fixed various bugs
- Updated floDapps
This commit is contained in:
sairajzero 2022-04-02 02:08:04 +05:30
parent 2a0302eb19
commit 7cbeb5a2c6
2 changed files with 261 additions and 276 deletions

View File

@ -1,4 +1,4 @@
(function(EXPORTS) { //floDapps v2.2.0 (function(EXPORTS) { //floDapps v2.2.0a
/* General functions for FLO Dapps*/ /* General functions for FLO Dapps*/
//'use strict'; //'use strict';
const floDapps = EXPORTS; const floDapps = EXPORTS;
@ -146,16 +146,15 @@
}) })
}); });
function getCredentials() { var keyInput = type => new Promise((resolve, reject) => {
let inputVal = prompt(`Enter ${type}: `)
if (inputVal === null)
reject(null)
else
resolve(inputVal)
});
const inputFn = getCredentials.privKeyInput || function getCredentials() {
(type => new Promise((resolve, reject) => {
let inputVal = prompt(`Enter ${type}: `)
if (inputVal === null)
reject(null)
else
resolve(inputVal)
}));
const readSharesFromIDB = indexArr => new Promise((resolve, reject) => { const readSharesFromIDB = indexArr => new Promise((resolve, reject) => {
var promises = [] var promises = []
@ -195,7 +194,7 @@
.catch(error => reject(error)) .catch(error => reject(error))
} else { } else {
var privKey; var privKey;
inputFn("PRIVATE_KEY").then(result => { keyInput("PRIVATE_KEY").then(result => {
if (!result) if (!result)
return reject("Empty Private Key") return reject("Empty Private Key")
var floID = floCrypto.getFloID(result) var floID = floCrypto.getFloID(result)
@ -229,7 +228,7 @@
if (key.length == 52) if (key.length == 52)
resolve(key) resolve(key)
else { else {
inputFn("PIN/Password").then(pwd => { keyInput("PIN/Password").then(pwd => {
try { try {
let privKey = Crypto.AES.decrypt(key, pwd); let privKey = Crypto.AES.decrypt(key, pwd);
resolve(privKey) resolve(privKey)
@ -327,7 +326,7 @@
floDapps.setCustomStartupLogger = fn => fn instanceof Function ? startUpLog = fn : false; floDapps.setCustomStartupLogger = fn => fn instanceof Function ? startUpLog = fn : false;
floDapps.setCustomPrivKeyInput = fn => fn instanceof Function ? customFn = fn : false; floDapps.setCustomPrivKeyInput = fn => fn instanceof Function ? keyInput = fn : false;
floDapps.setAppObjectStores = appObs => initIndexedDB.appObs = appObs; floDapps.setAppObjectStores = appObs => initIndexedDB.appObs = appObs;

View File

@ -1,176 +1,170 @@
const messenger = { (function() {
const messenger = window.messenger = {};
util: { function sendRaw(message, recipient, type, encrypt = null, comment = undefined) {
return new Promise((resolve, reject) => {
if (!floCrypto.validateAddr(recipient))
return reject("Invalid Recipient floID");
sendRaw(message, recipient, type, encrypt = null, comment = undefined) { if ([true, null].includes(encrypt) && recipient in floGlobals.pubKeys)
return new Promise((resolve, reject) => { message = floCrypto.encryptData(message, floGlobals.pubKeys[recipient])
if (!floCrypto.validateAddr(recipient)) else if (encrypt === true)
return reject("Invalid Recipient floID"); return reject("recipient's pubKey not found")
let options = {
receiverID: recipient,
}
if (comment)
options.comment = comment
floCloudAPI.sendApplicationData(message, type, options)
.then(result => resolve(result))
.catch(error => reject(error))
})
}
if ([true, null].includes(encrypt) && recipient in floGlobals.pubKeys) function encrypt(value, key = floGlobals.appendix.AESKey) {
message = floCrypto.encryptData(message, floGlobals.pubKeys[recipient]) return Crypto.AES.encrypt(value, key)
else if (encrypt === true) }
return reject("recipient's pubKey not found")
let options = { function decrypt(value, key = floGlobals.appendix.AESKey) {
receiverID: recipient, return Crypto.AES.decrypt(value, key)
} }
if (comment)
options.comment = comment function addMark(key, mark) {
floCloudAPI.sendApplicationData(message, type, options) return new Promise((resolve, reject) => {
compactIDB.readData("marked", key).then(result => {
if (!result)
result = [mark];
else if (!result.includes(mark))
result.push(mark);
else
return resolve("Mark already exist");
compactIDB.writeData("marked", result, key)
.then(result => resolve(result)) .then(result => resolve(result))
.catch(error => reject(error)) .catch(error => reject(error))
}) }).catch(error => reject(error))
}, })
}
encrypt(value, key = floGlobals.appendix.AESKey) { function removeMark(key, mark) {
return Crypto.AES.encrypt(value, key) return new Promise((resolve, reject) => {
}, compactIDB.readData("marked", key).then(result => {
if (!result || !result.includes(mark))
decrypt(value, key = floGlobals.appendix.AESKey) { return resolve("Mark doesnot exist")
return Crypto.AES.decrypt(value, key) else {
}, result.splice(result.indexOf(mark),
1); //remove the mark from the list of marks
addMark(key, mark) {
return new Promise((resolve, reject) => {
compactIDB.readData("marked", key).then(result => {
if (!result)
result = [mark];
else if (!result.includes(mark))
result.push(mark);
else
return resolve("Mark already exist");
compactIDB.writeData("marked", result, key) compactIDB.writeData("marked", result, key)
.then(result => resolve(result)) .then(result => resolve("Mark removed"))
.catch(error => reject(error)) .catch(error => reject(error))
}).catch(error => reject(error)) }
}) }).catch(error => reject(error))
}, })
}
removeMark(key, mark) { const UIcallback = {
return new Promise((resolve, reject) => { group: (d, e) => console.log(d, e),
compactIDB.readData("marked", key).then(result => { direct: (d, e) => console.log(d, e)
if (!result || !result.includes(mark)) }
return resolve("Mark doesnot exist")
else {
result.splice(result.indexOf(mark),
1); //remove the mark from the list of marks
compactIDB.writeData("marked", result, key)
.then(result => resolve("Mark removed"))
.catch(error => reject(error))
}
}).catch(error => reject(error))
})
},
UIcallback: { function groupConn(groupID) {
group: (d, e) => console.log(d, e), console.debug(UIcallback);
direct: (d, e) => console.log(d, e) let callbackFn = function(dataSet, error) {
}, if (error)
return console.error(error)
groupConn(groupID) { console.info(dataSet)
let utilFn = { let newInbox = {
encrypt: this.encrypt, messages: {}
decrypt: this.decrypt,
UIcallback: this.UIcallback["group"],
addMark: this.addMark
} }
let callbackFn = function(dataSet, error) { let infoChange = false;
if (error) for (let vc in dataSet) {
return console.error(error) if (groupID !== dataSet[vc].receiverID ||
console.info(dataSet) !floGlobals.groups[groupID].members.includes(dataSet[vc].senderID))
let newInbox = { continue;
messages: {} try {
} let data = {
let infoChange = false; time: dataSet[vc].time,
for (let vc in dataSet) { sender: dataSet[vc].senderID,
if (groupID !== dataSet[vc].receiverID || groupID: dataSet[vc].receiverID
!floGlobals.groups[groupID].members.includes(dataSet[vc].senderID))
continue;
try {
let data = {
time: dataSet[vc].time,
sender: dataSet[vc].senderID,
groupID: dataSet[vc].receiverID
}
let k = floGlobals.groups[groupID].eKey;
if (floGlobals.expiredKeys[groupID]) {
var ex = Object.keys(floGlobals.expiredKeys[groupID]).sort()
while (ex.lenght && vc > ex[0]) ex.shift()
if (ex.length)
k = floGlobals.expiredKeys[groupID][ex.shift()]
}
dataSet[vc].message = utilFn.decrypt(dataSet[vc].message, k)
//store the pubKey if not stored already
floDapps.storePubKey(dataSet[vc].senderID, dataSet[vc].pubKey)
if (dataSet[vc].type === "GROUP_MSG")
data.message = utilFn.encrypt(dataSet[vc].message);
else if (data.sender === floGlobals.groups[groupID].admin) {
let groupInfo = floGlobals.groups[groupID]
data.admin = true;
if (dataSet[vc].type === "ADD_MEMBERS") {
data.newMembers = dataSet[vc].message.split("|")
data.note = dataSet[vc].comment
groupInfo.members = [...new Set(groupInfo.members.concat(data
.newMembers))]
} else if (dataSet[vc].type === "RM_MEMBERS") {
data.rmMembers = dataSet[vc].message.split("|")
data.note = dataSet[vc].comment
groupInfo.members = groupInfo.members.filter(m => !data.rmMembers
.includes(m))
if (data.rmMembers.includes(myFloID))
groupInfo.status = false
} else if (dataSet[vc].type === "UP_DESCRIPTION") {
data.description = dataSet[vc].message
groupInfo.description = data.description
} else if (dataSet[vc].type === "UP_NAME") {
data.name = dataSet[vc].message
groupInfo.name = data.name
}
infoChange = true;
}
compactIDB.addData("messages", {
...data
}, `${groupID}|${vc}`)
if (data.message)
data.message = utilFn.decrypt(data.message);
newInbox.messages[vc] = data;
console.log(data)
if (data.sender !== myFloID)
utilFn.addMark(data.groupID, "unread")
if (!floGlobals.appendix[`lastReceived_${groupID}`] ||
floGlobals.appendix[`lastReceived_${groupID}`] < vc)
floGlobals.appendix[`lastReceived_${groupID}`] = vc;
} catch (error) {
console.log(error)
} }
} let k = floGlobals.groups[groupID].eKey;
compactIDB.writeData("appendix", floGlobals.appendix[`lastReceived_${groupID}`], if (floGlobals.expiredKeys[groupID]) {
`lastReceived_${groupID}`); var ex = Object.keys(floGlobals.expiredKeys[groupID]).sort()
if (infoChange) { while (ex.lenght && vc > ex[0]) ex.shift()
let newInfo = { if (ex.length)
...floGlobals.groups[groupID] k = floGlobals.expiredKeys[groupID][ex.shift()]
} }
newInfo.eKey = utilFn.encrypt(newInfo.eKey) dataSet[vc].message = decrypt(dataSet[vc].message, k)
compactIDB.writeData("groups", newInfo, groupID) //store the pubKey if not stored already
floDapps.storePubKey(dataSet[vc].senderID, dataSet[vc].pubKey)
if (dataSet[vc].type === "GROUP_MSG")
data.message = encrypt(dataSet[vc].message);
else if (data.sender === floGlobals.groups[groupID].admin) {
let groupInfo = floGlobals.groups[groupID]
data.admin = true;
if (dataSet[vc].type === "ADD_MEMBERS") {
data.newMembers = dataSet[vc].message.split("|")
data.note = dataSet[vc].comment
groupInfo.members = [...new Set(groupInfo.members.concat(data
.newMembers))]
} else if (dataSet[vc].type === "RM_MEMBERS") {
data.rmMembers = dataSet[vc].message.split("|")
data.note = dataSet[vc].comment
groupInfo.members = groupInfo.members.filter(m => !data.rmMembers
.includes(m))
if (data.rmMembers.includes(myFloID))
groupInfo.status = false
} else if (dataSet[vc].type === "UP_DESCRIPTION") {
data.description = dataSet[vc].message
groupInfo.description = data.description
} else if (dataSet[vc].type === "UP_NAME") {
data.name = dataSet[vc].message
groupInfo.name = data.name
}
infoChange = true;
}
compactIDB.addData("messages", {
...data
}, `${groupID}|${vc}`)
if (data.message)
data.message = decrypt(data.message);
newInbox.messages[vc] = data;
console.log(data)
if (data.sender !== myFloID)
addMark(data.groupID, "unread")
if (!floGlobals.appendix[`lastReceived_${groupID}`] ||
floGlobals.appendix[`lastReceived_${groupID}`] < vc)
floGlobals.appendix[`lastReceived_${groupID}`] = vc;
} catch (error) {
console.log(error)
} }
utilFn.UIcallback(newInbox)
} }
return floCloudAPI.requestApplicationData(null, { compactIDB.writeData("appendix", floGlobals.appendix[`lastReceived_${groupID}`],
receiverID: groupID, `lastReceived_${groupID}`);
lowerVectorClock: floGlobals.appendix[`lastReceived_${groupID}`] + 1, if (infoChange) {
callback: callbackFn let newInfo = {
}) ...floGlobals.groups[groupID]
}
newInfo.eKey = encrypt(newInfo.eKey)
compactIDB.writeData("groups", newInfo, groupID)
}
console.debug(newInbox);
UIcallback.group(newInbox);
} }
}, return floCloudAPI.requestApplicationData(null, {
receiverID: groupID,
lowerVectorClock: floGlobals.appendix[`lastReceived_${groupID}`] + 1,
callback: callbackFn
})
}
setUIcallbacks(directUI = null, groupUI = null) { messenger.setUIcallbacks = function(directUI = null, groupUI = null) {
if (directUI instanceof Function) if (directUI instanceof Function)
this.util.UIcallback["direct"] = directUI UIcallback["direct"] = directUI
if (groupUI instanceof Function) if (groupUI instanceof Function)
this.util.UIcallback["group"] = groupUI UIcallback["group"] = groupUI
}, }
initUserDB() { messenger.initUserDB = function() {
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
var obj = { var obj = {
messages: {}, messages: {},
@ -188,17 +182,17 @@ const messenger = {
resolve("Messenger UserDB Initated Successfully") resolve("Messenger UserDB Initated Successfully")
}).catch(error => reject(error)); }).catch(error => reject(error));
}) })
}, }
sendMessage(message, receiver) { messenger.sendMessage = function(message, receiver) {
return new Promise(async (resolve, reject) => { return new Promise(async (resolve, reject) => {
this.util.sendRaw(message, receiver, "MESSAGE").then(result => { sendRaw(message, receiver, "MESSAGE").then(result => {
let vc = Object.keys(result).pop() let vc = result.vectorClock;
let data = { let data = {
floID: receiver, floID: receiver,
time: result[vc].time, time: result.time,
category: 'sent', category: 'sent',
message: this.util.encrypt(message) message: encrypt(message)
} }
floGlobals.chats[receiver] = parseInt(vc) floGlobals.chats[receiver] = parseInt(vc)
compactIDB.writeData("chats", parseInt(vc), receiver) compactIDB.writeData("chats", parseInt(vc), receiver)
@ -211,9 +205,9 @@ const messenger = {
}); });
}).catch(error => reject(error)) }).catch(error => reject(error))
}) })
}, }
sendMail(subject, content, recipients, prev = null) { messenger.sendMail = function(subject, content, recipients, prev = null) {
return new Promise(async (resolve, reject) => { return new Promise(async (resolve, reject) => {
if (!Array.isArray(recipients)) if (!Array.isArray(recipients))
recipients = [recipients] recipients = [recipients]
@ -223,20 +217,18 @@ const messenger = {
ref: Date.now() + floCrypto.randString(8, true), ref: Date.now() + floCrypto.randString(8, true),
prev: prev prev: prev
} }
let promises = recipients.map(r => this.util.sendRaw(JSON.stringify(mail), r, "MAIL")) let promises = recipients.map(r => sendRaw(JSON.stringify(mail), r, "MAIL"))
Promise.allSettled(promises).then(results => { Promise.allSettled(promises).then(results => {
mail.time = Date.now(); mail.time = Date.now();
mail.from = myFloID mail.from = myFloID
mail.to = [] mail.to = []
results.forEach(r => { results.forEach(r => {
if (r.status === "fulfilled") { if (r.status === "fulfilled")
let vc = Object.keys(r.value).pop() mail.to.push(r.value.receiverID)
mail.to.push(r.value[vc].receiverID) });
}
})
if (mail.to.length === 0) if (mail.to.length === 0)
return reject(results) return reject(results)
mail.content = this.util.encrypt(content) mail.content = encrypt(content)
compactIDB.addData("mails", { compactIDB.addData("mails", {
...mail ...mail
}, mail.ref) }, mail.ref)
@ -246,17 +238,10 @@ const messenger = {
}); });
}) })
}) })
}, }
requestDirectInbox() { messenger.requestDirectInbox = function() {
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
let utilFn = {
encrypt: this.util.encrypt,
decrypt: this.util.decrypt,
UIcallback: this.util.UIcallback["direct"],
groupConn: this.util.groupConn,
addMark: this.util.addMark
}
let callbackFn = function(dataSet, error) { let callbackFn = function(dataSet, error) {
if (error) if (error)
return console.error(error) return console.error(error)
@ -279,7 +264,7 @@ const messenger = {
time: dataSet[vc].time, time: dataSet[vc].time,
floID: dataSet[vc].senderID, floID: dataSet[vc].senderID,
category: "received", category: "received",
message: utilFn.encrypt(dataSet[vc].message) message: encrypt(dataSet[vc].message)
} }
compactIDB.addData("messages", { compactIDB.addData("messages", {
...dm ...dm
@ -288,7 +273,7 @@ const messenger = {
compactIDB.writeData("chats", parseInt(vc), dm.floID) compactIDB.writeData("chats", parseInt(vc), dm.floID)
dm.message = dataSet[vc].message; dm.message = dataSet[vc].message;
newInbox.messages[vc] = dm; newInbox.messages[vc] = dm;
utilFn.addMark(dm.floID, "unread") addMark(dm.floID, "unread")
} else if (dataSet[vc].type === "MAIL") { } else if (dataSet[vc].type === "MAIL") {
//process as mail //process as mail
let data = JSON.parse(dataSet[vc].message); let data = JSON.parse(dataSet[vc].message);
@ -297,7 +282,7 @@ const messenger = {
from: dataSet[vc].senderID, from: dataSet[vc].senderID,
to: [myFloID], to: [myFloID],
subject: data.subject, subject: data.subject,
content: utilFn.encrypt(data.content), content: encrypt(data.content),
ref: data.ref, ref: data.ref,
prev: data.prev prev: data.prev
} }
@ -306,7 +291,7 @@ const messenger = {
}, mail.ref); }, mail.ref);
mail.content = data.content; mail.content = data.content;
newInbox.mails[mail.ref] = mail; newInbox.mails[mail.ref] = mail;
utilFn.addMark(mail.ref, "unread") addMark(mail.ref, "unread")
} else if (dataSet[vc].type === "CREATE_GROUP") { } else if (dataSet[vc].type === "CREATE_GROUP") {
//process create group //process create group
let groupInfo = JSON.parse(dataSet[vc].message); let groupInfo = JSON.parse(dataSet[vc].message);
@ -315,13 +300,13 @@ const messenger = {
floCrypto.verifySign(h, groupInfo.hash, groupInfo.pubKey) && floCrypto.verifySign(h, groupInfo.hash, groupInfo.pubKey) &&
floCrypto.getFloID(groupInfo.pubKey) === groupInfo.groupID) { floCrypto.getFloID(groupInfo.pubKey) === groupInfo.groupID) {
let eKey = groupInfo.eKey let eKey = groupInfo.eKey
groupInfo.eKey = utilFn.encrypt(eKey) groupInfo.eKey = encrypt(eKey)
compactIDB.writeData("groups", { compactIDB.writeData("groups", {
...groupInfo ...groupInfo
}, groupInfo.groupID) }, groupInfo.groupID)
groupInfo.eKey = eKey groupInfo.eKey = eKey
floGlobals.groups[groupInfo.groupID] = groupInfo floGlobals.groups[groupInfo.groupID] = groupInfo
utilFn.groupConn(groupInfo.groupID) groupConn(groupInfo.groupID)
newInbox.newgroups.push(groupInfo.groupID) newInbox.newgroups.push(groupInfo.groupID)
} }
} else if (dataSet[vc].type === "REVOKE_KEY") { } else if (dataSet[vc].type === "REVOKE_KEY") {
@ -332,7 +317,7 @@ const messenger = {
floGlobals.expiredKeys[r.groupID] = {} floGlobals.expiredKeys[r.groupID] = {}
floGlobals.expiredKeys[r.groupID][vc] = groupInfo.eKey floGlobals.expiredKeys[r.groupID][vc] = groupInfo.eKey
let eKey = r.newKey let eKey = r.newKey
groupInfo.eKey = utilFn.encrypt(eKey); groupInfo.eKey = encrypt(eKey);
compactIDB.writeData("groups", { compactIDB.writeData("groups", {
...groupInfo ...groupInfo
}, groupInfo.groupID) }, groupInfo.groupID)
@ -348,7 +333,8 @@ const messenger = {
} }
} }
compactIDB.writeData("appendix", floGlobals.appendix.lastReceived, "lastReceived"); compactIDB.writeData("appendix", floGlobals.appendix.lastReceived, "lastReceived");
utilFn.UIcallback(newInbox) console.debug(newInbox);
UIcallback.direct(newInbox)
} }
var options = { var options = {
@ -360,18 +346,18 @@ const messenger = {
.then(result => resolve(result)) .then(result => resolve(result))
.catch(error => reject(error)) .catch(error => reject(error))
}) })
}, }
getMail(mailRef) { messenger.getMail = function(mailRef) {
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
compactIDB.readData("mails", mailRef).then(mail => { compactIDB.readData("mails", mailRef).then(mail => {
mail.content = this.util.decrypt(mail.content) mail.content = decrypt(mail.content)
resolve(mail) resolve(mail)
}).catch(error => reject(error)) }).catch(error => reject(error))
}); });
}, }
getChatOrder(type = ["direct", "group", "mixed"]) { messenger.getChatOrder = function(type = ["direct", "group", "mixed"]) {
if (typeof type === "string") if (typeof type === "string")
type = type.split('|') type = type.split('|')
let result = {} let result = {}
@ -388,13 +374,13 @@ const messenger = {
if (type.length === 1) if (type.length === 1)
result = result[type[0]] result = result[type[0]]
return result return result
}, }
storeContact(floID, name) { messenger.storeContact = function(floID, name) {
return floDapps.storeContact(floID, name) return floDapps.storeContact(floID, name)
}, }
loadDataFromIDB(dataList = 'default') { const loadDataFromIDB = messenger.loadDataFromIDB = function(dataList = 'default') {
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
if (dataList === 'default') if (dataList === 'default')
dataList = ["mails", "marked", "groups", "chats", "appendix"] dataList = ["mails", "marked", "groups", "chats", "appendix"]
@ -415,16 +401,16 @@ const messenger = {
if (dataList.includes("messages")) if (dataList.includes("messages"))
for (let m in data.messages) for (let m in data.messages)
if (data.messages[m].message) if (data.messages[m].message)
data.messages[m].message = this.util.decrypt(data.messages[m].message, AESKey) data.messages[m].message = decrypt(data.messages[m].message, AESKey)
if (dataList.includes("mails")) if (dataList.includes("mails"))
for (let m in data.mails) for (let m in data.mails)
data.mails[m].content = this.util.decrypt(data.mails[m].content, AESKey) data.mails[m].content = decrypt(data.mails[m].content, AESKey)
if (dataList.includes("groups")) if (dataList.includes("groups"))
for (let g in data.groups) for (let g in data.groups)
data.groups[g].eKey = this.util.decrypt(data.groups[g].eKey, AESKey) data.groups[g].eKey = decrypt(data.groups[g].eKey, AESKey)
if (dataList.includes("gkeys")) if (dataList.includes("gkeys"))
for (let k in data.gkeys) for (let k in data.gkeys)
data.gkeys[k] = this.util.decrypt(data.gkeys[k], AESKey) data.gkeys[k] = decrypt(data.gkeys[k], AESKey)
resolve(data) resolve(data)
} catch (error) { } catch (error) {
reject("Corrupted AES Key"); reject("Corrupted AES Key");
@ -441,37 +427,37 @@ const messenger = {
} }
}).catch(error => reject(error)) }).catch(error => reject(error))
}) })
}, }
addMark(key, mark) { messenger.addMark = function(key, mark) {
if (floGlobals.marked.hasOwnProperty(key) && !floGlobals.marked[key].includes(mark)) if (floGlobals.marked.hasOwnProperty(key) && !floGlobals.marked[key].includes(mark))
floGlobals.marked[key].push(mark) floGlobals.marked[key].push(mark)
return this.util.addMark(key, mark) return addMark(key, mark)
}, }
removeMark(key, mark) { messenger.removeMark = function(key, mark) {
if (floGlobals.marked.hasOwnProperty(key)) if (floGlobals.marked.hasOwnProperty(key))
floGlobals.marked[key] = floGlobals.marked[key].filter(v => v !== mark) floGlobals.marked[key] = floGlobals.marked[key].filter(v => v !== mark)
return this.util.removeMark(key, mark) return removeMark(key, mark)
}, }
addChat(chatID) { messenger.addChat = function(chatID) {
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
compactIDB.addData("chats", 0, chatID) compactIDB.addData("chats", 0, chatID)
.then(result => resolve("Added chat")) .then(result => resolve("Added chat"))
.catch(error => reject(error)) .catch(error => reject(error))
}) })
}, }
rmChat(chatID) { messenger.rmChat = function(chatID) {
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
compactIDB.removeData("chats", chatID) compactIDB.removeData("chats", chatID)
.then(result => resolve("Chat removed")) .then(result => resolve("Chat removed"))
.catch(error => reject(error)) .catch(error => reject(error))
}) })
}, }
clearChat(chatID) { messenger.clearChat = function(chatID) {
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
let options = { let options = {
lowerKey: `${chatID}|`, lowerKey: `${chatID}|`,
@ -486,9 +472,9 @@ const messenger = {
.catch(error => reject(error)) .catch(error => reject(error))
}).catch(error => reject(error)) }).catch(error => reject(error))
}) })
}, }
getChat(chatID) { messenger.getChat = function(chatID) {
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
let options = { let options = {
lowerKey: `${chatID}|`, lowerKey: `${chatID}|`,
@ -497,15 +483,15 @@ const messenger = {
compactIDB.searchData("messages", options).then(result => { compactIDB.searchData("messages", options).then(result => {
for (let i in result) for (let i in result)
if (result[i].message) if (result[i].message)
result[i].message = this.util.decrypt(result[i].message) result[i].message = decrypt(result[i].message)
resolve(result) resolve(result)
}).catch(error => reject(error)) }).catch(error => reject(error))
}) })
}, }
backupData() { messenger.backupData = function() {
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
this.loadDataFromIDB("all").then(data => { loadDataFromIDB("all").then(data => {
delete data.appendix.AESKey; delete data.appendix.AESKey;
data.contacts = floGlobals.contacts; data.contacts = floGlobals.contacts;
data.pubKeys = floGlobals.pubKeys; data.pubKeys = floGlobals.pubKeys;
@ -513,7 +499,7 @@ const messenger = {
let blobData = { let blobData = {
floID: myFloID, floID: myFloID,
pubKey: myPubKey, pubKey: myPubKey,
data: this.util.encrypt(data, myPrivKey), data: encrypt(data, myPrivKey),
} }
blobData.sign = floCrypto.signData(blobData.data, myPrivKey); blobData.sign = floCrypto.signData(blobData.data, myPrivKey);
resolve(new Blob([JSON.stringify(blobData)], { resolve(new Blob([JSON.stringify(blobData)], {
@ -521,9 +507,9 @@ const messenger = {
})); }));
}).catch(error => reject(error)) }).catch(error => reject(error))
}) })
}, }
parseBackup(blob) { const parseBackup = messenger.parseBackup = function(blob) {
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
if (blob instanceof Blob || blob instanceof File) { if (blob instanceof Blob || blob instanceof File) {
let reader = new FileReader(); let reader = new FileReader();
@ -535,7 +521,7 @@ const messenger = {
reject("Invalid Backup file: Incorrect floID"); reject("Invalid Backup file: Incorrect floID");
else { else {
try { try {
let data = this.util.decrypt(blobData.data, myPrivKey) let data = decrypt(blobData.data, myPrivKey)
try { try {
data = JSON.parse(decodeURIComponent(escape(atob(data)))); data = JSON.parse(decodeURIComponent(escape(atob(data))));
resolve(data) resolve(data)
@ -551,24 +537,24 @@ const messenger = {
} else } else
reject("Backup is not a valid File (or) Blob") reject("Backup is not a valid File (or) Blob")
}) })
}, }
restoreData(arg) { messenger.restoreData = function(arg) {
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
if (arg instanceof Blob || arg instanceof File) if (arg instanceof Blob || arg instanceof File)
var parseData = this.parseBackup var parseData = parseBackup
else else
var parseData = data => new Promise((res, rej) => res(data)) var parseData = data => new Promise((res, rej) => res(data))
parseData(arg).then(data => { parseData(arg).then(data => {
for (let m in data.messages) for (let m in data.messages)
if (data.messages[m].message) if (data.messages[m].message)
data.messages[m].message = this.util.encrypt(data.messages[m].message) data.messages[m].message = encrypt(data.messages[m].message)
for (let m in data.mail) for (let m in data.mail)
data.mails[m].content = this.util.encrypt(data.mails[m].content) data.mails[m].content = encrypt(data.mails[m].content)
for (let k in data.gkeys) for (let k in data.gkeys)
data.gkeys[k] = this.util.encrypt(data.gkeys[k]) data.gkeys[k] = encrypt(data.gkeys[k])
for (let g in data.groups) for (let g in data.groups)
data.groups[g].eKey = this.util.encrypt(data.groups[g].eKey) data.groups[g].eKey = encrypt(data.groups[g].eKey)
for (let c in data.chats) for (let c in data.chats)
if (data.chats[c] <= floGlobals.chats[c]) if (data.chats[c] <= floGlobals.chats[c])
delete data.chats[c] delete data.chats[c]
@ -604,9 +590,9 @@ const messenger = {
.catch(error => reject("Restore Failed: Unable to write to IDB")) .catch(error => reject("Restore Failed: Unable to write to IDB"))
}).catch(error => reject(error)) }).catch(error => reject(error))
}) })
}, }
clearUserData() { messenger.clearUserData = function() {
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
let promises = [ let promises = [
compactIDB.deleteDB(), compactIDB.deleteDB(),
@ -616,11 +602,11 @@ const messenger = {
.then(result => resolve("User Data cleared")) .then(result => resolve("User Data cleared"))
.catch(error => reject(error)) .catch(error => reject(error))
}) })
}, }
//group feature //group feature
createGroup(groupname, description = '') { messenger.createGroup = function(groupname, description = '') {
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
if (!groupname) return reject("Invalid Group Name") if (!groupname) return reject("Invalid Group Name")
let id = floCrypto.generateNewID(); let id = floCrypto.generateNewID();
@ -636,43 +622,43 @@ const messenger = {
let h = ["groupID", "created", "admin"].map(x => groupInfo[x]).join('|') let h = ["groupID", "created", "admin"].map(x => groupInfo[x]).join('|')
groupInfo.hash = floCrypto.signData(h, id.privKey) groupInfo.hash = floCrypto.signData(h, id.privKey)
let eKey = floCrypto.randString(16, false) let eKey = floCrypto.randString(16, false)
groupInfo.eKey = this.util.encrypt(eKey) groupInfo.eKey = encrypt(eKey)
p1 = compactIDB.addData("groups", groupInfo, id.floID) p1 = compactIDB.addData("groups", groupInfo, id.floID)
p2 = compactIDB.addData("gkeys", this.util.encrypt(id.privKey), id.floID) p2 = compactIDB.addData("gkeys", encrypt(id.privKey), id.floID)
Promise.all([p1, p2]).then(r => { Promise.all([p1, p2]).then(r => {
groupInfo.eKey = eKey groupInfo.eKey = eKey
floGlobals.groups[id.floID] = groupInfo; floGlobals.groups[id.floID] = groupInfo;
this.util.groupConn(id.floID) groupConn(id.floID)
resolve(groupInfo) resolve(groupInfo)
}).catch(e => reject(e)) }).catch(e => reject(e))
}) })
}, }
changeGroupName(groupID, name) { messenger.changeGroupName = function(groupID, name) {
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
let groupInfo = floGlobals.groups[groupID] let groupInfo = floGlobals.groups[groupID]
if (myFloID !== groupInfo.admin) if (myFloID !== groupInfo.admin)
return reject("Access denied: Admin only!") return reject("Access denied: Admin only!")
let message = this.util.encrypt(name, groupInfo.eKey) let message = encrypt(name, groupInfo.eKey)
this.util.sendRaw(message, groupID, "UP_NAME", false) sendRaw(message, groupID, "UP_NAME", false)
.then(result => resolve('Name updated')) .then(result => resolve('Name updated'))
.catch(error => reject(error)) .catch(error => reject(error))
}) })
}, }
changeGroupDescription(groupID, description) { messenger.changeGroupDescription = function(groupID, description) {
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
let groupInfo = floGlobals.groups[groupID] let groupInfo = floGlobals.groups[groupID]
if (myFloID !== groupInfo.admin) if (myFloID !== groupInfo.admin)
return reject("Access denied: Admin only!") return reject("Access denied: Admin only!")
let message = this.util.encrypt(description, groupInfo.eKey) let message = encrypt(description, groupInfo.eKey)
this.util.sendRaw(message, groupID, "UP_DESCRIPTION", false) sendRaw(message, groupID, "UP_DESCRIPTION", false)
.then(result => resolve('Description updated')) .then(result => resolve('Description updated'))
.catch(error => reject(error)) .catch(error => reject(error))
}) })
}, }
addGroupMembers(groupID, newMem, note = undefined) { messenger.addGroupMembers = function(groupID, newMem, note = undefined) {
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
if (!Array.isArray(newMem) && typeof newMem === "string") if (!Array.isArray(newMem) && typeof newMem === "string")
newMem = [newMem] newMem = [newMem]
@ -694,7 +680,7 @@ const messenger = {
//send groupInfo to new newMem //send groupInfo to new newMem
let k = groupInfo.eKey let k = groupInfo.eKey
groupInfo = JSON.stringify(groupInfo) groupInfo = JSON.stringify(groupInfo)
let promises = newMem.map(m => this.util.sendRaw(groupInfo, m, "CREATE_GROUP", true)) let promises = newMem.map(m => sendRaw(groupInfo, m, "CREATE_GROUP", true));
Promise.allSettled(promises).then(results => { Promise.allSettled(promises).then(results => {
let success = [], let success = [],
failed = []; failed = [];
@ -704,15 +690,15 @@ const messenger = {
else if (results[i].status === "rejected") else if (results[i].status === "rejected")
failed.push(newMem[i]) failed.push(newMem[i])
console.log(success.join("|"), k) console.log(success.join("|"), k)
let message = this.util.encrypt(success.join("|"), k) let message = encrypt(success.join("|"), k)
this.util.sendRaw(message, groupID, "ADD_MEMBERS", false, note) sendRaw(message, groupID, "ADD_MEMBERS", false, note)
.then(r => resolve(`Members added: ${success}`)) .then(r => resolve(`Members added: ${success}`))
.catch(e => reject(e)) .catch(e => reject(e))
}) })
}) })
}, }
rmGroupMembers(groupID, rmMem, note = undefined) { messenger.rmGroupMembers = function(groupID, rmMem, note = undefined) {
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
if (!Array.isArray(rmMem) && typeof rmMem === "string") if (!Array.isArray(rmMem) && typeof rmMem === "string")
rmMem = [rmMem] rmMem = [rmMem]
@ -722,46 +708,46 @@ const messenger = {
return reject(`Invalid members: ${imem}`) return reject(`Invalid members: ${imem}`)
if (myFloID !== groupInfo.admin) if (myFloID !== groupInfo.admin)
return reject("Access denied: Admin only!") return reject("Access denied: Admin only!")
let message = this.util.encrypt(rmMem.join("|"), groupInfo.eKey) let message = encrypt(rmMem.join("|"), groupInfo.eKey)
p1 = this.util.sendRaw(message, groupID, "RM_MEMBERS", false, note) p1 = sendRaw(message, groupID, "RM_MEMBERS", false, note)
groupInfo.members = groupInfo.members.filter(m => !rmMem.includes(m)) groupInfo.members = groupInfo.members.filter(m => !rmMem.includes(m))
p2 = this.revokeKey(groupID) p2 = revokeKey(groupID)
Promise.all([p1, p2]) Promise.all([p1, p2])
.then(r => resolve(`Members removed: ${rmMem}`)) .then(r => resolve(`Members removed: ${rmMem}`))
.catch(e => reject(e)) .catch(e => reject(e))
}) })
}, }
revokeKey(groupID) { const revokeKey = messenger.revokeKey = function(groupID) {
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
let groupInfo = floGlobals.groups[groupID] let groupInfo = floGlobals.groups[groupID]
if (myFloID !== groupInfo.admin) if (myFloID !== groupInfo.admin)
return reject("Access denied: Admin only!") return reject("Access denied: Admin only!")
let newKey = floCrypto.randString(16, false); let newKey = floCrypto.randString(16, false);
Promise.all(groupInfo.members.map(m => this.util.sendRaw(JSON.stringify({ Promise.all(groupInfo.members.map(m => sendRaw(JSON.stringify({
newKey, newKey,
groupID groupID
}), m, "REVOKE_KEY", true))).then(result => { }), m, "REVOKE_KEY", true))).then(result => {
resolve("Group key revoked") resolve("Group key revoked")
}).catch(error => reject(error)) }).catch(error => reject(error))
}) })
}, }
sendGroupMessage(message, groupID) { messenger.sendGroupMessage = function(message, groupID) {
return new Promise(async (resolve, reject) => { return new Promise(async (resolve, reject) => {
let k = floGlobals.groups[groupID].eKey let k = floGlobals.groups[groupID].eKey
message = this.util.encrypt(message, k) message = encrypt(message, k)
this.util.sendRaw(message, groupID, "GROUP_MSG", false) sendRaw(message, groupID, "GROUP_MSG", false)
.then(result => resolve(`${groupID}: ${message}`)) .then(result => resolve(`${groupID}: ${message}`))
.catch(error => reject(error)) .catch(error => reject(error))
}) })
}, }
requestGroupInbox() { messenger.requestGroupInbox = function() {
return new Promise((resolve) => { return new Promise((resolve) => {
let promises = [] let promises = []
let reqFn = (g) => new Promise((res, rej) => { let reqFn = (g) => new Promise((res, rej) => {
this.util.groupConn(g) groupConn(g)
.then(r => res([g, r])) .then(r => res([g, r]))
.catch(e => rej([g, e])) .catch(e => rej([g, e]))
}) })
@ -786,4 +772,4 @@ const messenger = {
}) })
}) })
} }
} })();