Pipleline and multisig
This commit is contained in:
parent
d3bb38c91d
commit
e4f5d41ade
@ -14,6 +14,7 @@
|
|||||||
|
|
||||||
const UI = {
|
const UI = {
|
||||||
group: (d, e) => console.log(d, e),
|
group: (d, e) => console.log(d, e),
|
||||||
|
pipeline: (d, e) => console.log(d, e),
|
||||||
direct: (d, e) => console.log(d, e),
|
direct: (d, e) => console.log(d, e),
|
||||||
chats: (c) => console.log(c),
|
chats: (c) => console.log(c),
|
||||||
mails: (m) => console.log(m),
|
mails: (m) => console.log(m),
|
||||||
@ -30,6 +31,9 @@
|
|||||||
groupChat: {
|
groupChat: {
|
||||||
set: ui_fn => UI.group = ui_fn
|
set: ui_fn => UI.group = ui_fn
|
||||||
},
|
},
|
||||||
|
pipeline: {
|
||||||
|
set: ui_fn => UI.pipeline = ui_fn
|
||||||
|
},
|
||||||
mails: {
|
mails: {
|
||||||
set: ui_fn => UI.mails = ui_fn
|
set: ui_fn => UI.mails = ui_fn
|
||||||
},
|
},
|
||||||
@ -46,6 +50,9 @@
|
|||||||
groups: {
|
groups: {
|
||||||
get: () => _loaded.groups
|
get: () => _loaded.groups
|
||||||
},
|
},
|
||||||
|
pipeline: {
|
||||||
|
get: () => _loaded.pipeline
|
||||||
|
},
|
||||||
blocked: {
|
blocked: {
|
||||||
get: () => _loaded.blocked
|
get: () => _loaded.blocked
|
||||||
},
|
},
|
||||||
@ -54,7 +61,8 @@
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
var directConnID, groupConnID = {};
|
var directConnID, groupConnID = {},
|
||||||
|
pipeConnID = {};
|
||||||
messenger.conn = {};
|
messenger.conn = {};
|
||||||
Object.defineProperties(messenger.conn, {
|
Object.defineProperties(messenger.conn, {
|
||||||
direct: {
|
direct: {
|
||||||
@ -125,101 +133,6 @@
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
function requestGroupInbox(groupID) {
|
|
||||||
if (groupConnID[groupID]) { //close existing request connection (if any)
|
|
||||||
floCloudAPI.closeRequest(groupConnID[groupID]);
|
|
||||||
delete groupConnID[groupID];
|
|
||||||
}
|
|
||||||
let callbackFn = function(dataSet, error) {
|
|
||||||
if (error)
|
|
||||||
return console.error(error)
|
|
||||||
console.info(dataSet)
|
|
||||||
let newInbox = {
|
|
||||||
messages: {}
|
|
||||||
}
|
|
||||||
let infoChange = false;
|
|
||||||
for (let vc in dataSet) {
|
|
||||||
if (groupID !== dataSet[vc].receiverID ||
|
|
||||||
!_loaded.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 = _loaded.groups[groupID].eKey;
|
|
||||||
if (expiredKeys[groupID]) {
|
|
||||||
var ex = Object.keys(expiredKeys[groupID]).sort()
|
|
||||||
while (ex.length && vc > ex[0]) ex.shift()
|
|
||||||
if (ex.length)
|
|
||||||
k = expiredKeys[groupID][ex.shift()]
|
|
||||||
}
|
|
||||||
dataSet[vc].message = 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 = encrypt(dataSet[vc].message);
|
|
||||||
else if (data.sender === _loaded.groups[groupID].admin) {
|
|
||||||
let groupInfo = _loaded.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(user.id)) {
|
|
||||||
disableGroup(groupID);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
} 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;
|
|
||||||
if (data.sender !== user.id)
|
|
||||||
addMark(data.groupID, "unread")
|
|
||||||
if (!_loaded.appendix[`lastReceived_${groupID}`] ||
|
|
||||||
_loaded.appendix[`lastReceived_${groupID}`] < vc)
|
|
||||||
_loaded.appendix[`lastReceived_${groupID}`] = vc;
|
|
||||||
} catch (error) {
|
|
||||||
console.log(error)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
compactIDB.writeData("appendix", _loaded.appendix[`lastReceived_${groupID}`],
|
|
||||||
`lastReceived_${groupID}`);
|
|
||||||
if (infoChange) {
|
|
||||||
let newInfo = {
|
|
||||||
..._loaded.groups[groupID]
|
|
||||||
}
|
|
||||||
newInfo.eKey = encrypt(newInfo.eKey)
|
|
||||||
compactIDB.writeData("groups", newInfo, groupID)
|
|
||||||
}
|
|
||||||
console.debug(newInbox);
|
|
||||||
UI.group(newInbox);
|
|
||||||
}
|
|
||||||
floCloudAPI.requestApplicationData(null, {
|
|
||||||
receiverID: groupID,
|
|
||||||
lowerVectorClock: _loaded.appendix[`lastReceived_${groupID}`] + 1,
|
|
||||||
callback: callbackFn
|
|
||||||
}).then(conn_id => groupConnID[groupID] = conn_id)
|
|
||||||
.catch(error => console.error(`request-group(${groupID}):`, error))
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
const initUserDB = function() {
|
const initUserDB = function() {
|
||||||
return new Promise((resolve, reject) => {
|
return new Promise((resolve, reject) => {
|
||||||
var obj = {
|
var obj = {
|
||||||
@ -230,6 +143,7 @@
|
|||||||
groups: {},
|
groups: {},
|
||||||
gkeys: {},
|
gkeys: {},
|
||||||
blocked: {},
|
blocked: {},
|
||||||
|
pipeline: {},
|
||||||
flodata: {},
|
flodata: {},
|
||||||
appendix: {},
|
appendix: {},
|
||||||
userSettings: {}
|
userSettings: {}
|
||||||
@ -321,11 +235,96 @@
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
const requestDirectInbox = function() {
|
const processData = {};
|
||||||
|
processData.direct = function() {
|
||||||
|
return (unparsed, newInbox) => {
|
||||||
|
//store the pubKey if not stored already
|
||||||
|
floDapps.storePubKey(unparsed.senderID, unparsed.pubKey);
|
||||||
|
if (_loaded.blocked.has(unparsed.senderID) && unparsed.type !== "REVOKE_KEY")
|
||||||
|
throw "blocked-user";
|
||||||
|
if (unparsed.message instanceof Object && "secret" in unparsed.message)
|
||||||
|
unparsed.message = floDapps.user.decrypt(unparsed.message);
|
||||||
|
switch (unparsed.type) {
|
||||||
|
case "MESSAGE": { //process as message
|
||||||
|
let dm = {
|
||||||
|
time: unparsed.time,
|
||||||
|
floID: unparsed.senderID,
|
||||||
|
category: "received",
|
||||||
|
message: encrypt(unparsed.message)
|
||||||
|
}
|
||||||
|
compactIDB.addData("messages", {
|
||||||
|
...dm
|
||||||
|
}, `${dm.floID}|${vc}`)
|
||||||
|
_loaded.chats[dm.floID] = parseInt(vc)
|
||||||
|
compactIDB.writeData("chats", parseInt(vc), dm.floID)
|
||||||
|
dm.message = unparsed.message;
|
||||||
|
newInbox.messages[vc] = dm;
|
||||||
|
addMark(dm.floID, "unread");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case "MAIL": { //process as mail
|
||||||
|
let data = JSON.parse(unparsed.message);
|
||||||
|
let mail = {
|
||||||
|
time: unparsed.time,
|
||||||
|
from: unparsed.senderID,
|
||||||
|
to: [unparsed.receiverID],
|
||||||
|
subject: data.subject,
|
||||||
|
content: encrypt(data.content),
|
||||||
|
ref: data.ref,
|
||||||
|
prev: data.prev
|
||||||
|
}
|
||||||
|
compactIDB.addData("mails", {
|
||||||
|
...mail
|
||||||
|
}, mail.ref);
|
||||||
|
mail.content = data.content;
|
||||||
|
newInbox.mails[mail.ref] = mail;
|
||||||
|
addMark(mail.ref, "unread");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case "CREATE_GROUP": { //process create group
|
||||||
|
let groupInfo = JSON.parse(unparsed.message);
|
||||||
|
let h = ["groupID", "created", "admin"].map(x => groupInfo[x]).join('|')
|
||||||
|
if (groupInfo.admin === unparsed.senderID &&
|
||||||
|
floCrypto.verifySign(h, groupInfo.hash, groupInfo.pubKey) &&
|
||||||
|
floCrypto.getFloID(groupInfo.pubKey) === groupInfo.groupID) {
|
||||||
|
let eKey = groupInfo.eKey
|
||||||
|
groupInfo.eKey = encrypt(eKey)
|
||||||
|
compactIDB.writeData("groups", {
|
||||||
|
...groupInfo
|
||||||
|
}, groupInfo.groupID)
|
||||||
|
groupInfo.eKey = eKey
|
||||||
|
_loaded.groups[groupInfo.groupID] = groupInfo
|
||||||
|
requestGroupInbox(groupInfo.groupID)
|
||||||
|
newInbox.newgroups.push(groupInfo.groupID)
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case "REVOKE_KEY": { //revoke group key
|
||||||
|
let r = JSON.parse(unparsed.message);
|
||||||
|
let groupInfo = _loaded.groups[r.groupID]
|
||||||
|
if (unparsed.senderID === groupInfo.admin) {
|
||||||
|
if (typeof expiredKeys[r.groupID] !== "object")
|
||||||
|
expiredKeys[r.groupID] = {}
|
||||||
|
expiredKeys[r.groupID][vc] = groupInfo.eKey
|
||||||
|
let eKey = r.newKey
|
||||||
|
groupInfo.eKey = encrypt(eKey);
|
||||||
|
compactIDB.writeData("groups", {
|
||||||
|
...groupInfo
|
||||||
|
}, groupInfo.groupID)
|
||||||
|
groupInfo.eKey = eKey
|
||||||
|
newInbox.keyrevoke.push(groupInfo.groupID)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function requestDirectInbox() {
|
||||||
if (directConnID) { //close existing request connection (if any)
|
if (directConnID) { //close existing request connection (if any)
|
||||||
floCloudAPI.closeRequest(directConnID);
|
floCloudAPI.closeRequest(directConnID);
|
||||||
directConnID = undefined;
|
directConnID = undefined;
|
||||||
}
|
}
|
||||||
|
const parseData = processData.direct();
|
||||||
let callbackFn = function(dataSet, error) {
|
let callbackFn = function(dataSet, error) {
|
||||||
if (error)
|
if (error)
|
||||||
return console.error(error)
|
return console.error(error)
|
||||||
@ -337,79 +336,7 @@
|
|||||||
}
|
}
|
||||||
for (let vc in dataSet) {
|
for (let vc in dataSet) {
|
||||||
try {
|
try {
|
||||||
//store the pubKey if not stored already
|
parseData(dataSet[vc], newInbox);
|
||||||
floDapps.storePubKey(dataSet[vc].senderID, dataSet[vc].pubKey);
|
|
||||||
if (_loaded.blocked.has(dataSet[vc].senderID) && dataSet[vc].type !== "REVOKE_KEY")
|
|
||||||
throw "blocked-user";
|
|
||||||
if (dataSet[vc].message instanceof Object && "secret" in dataSet[vc].message)
|
|
||||||
dataSet[vc].message = floDapps.user.decrypt(dataSet[vc].message);
|
|
||||||
if (dataSet[vc].type === "MESSAGE") {
|
|
||||||
//process as message
|
|
||||||
let dm = {
|
|
||||||
time: dataSet[vc].time,
|
|
||||||
floID: dataSet[vc].senderID,
|
|
||||||
category: "received",
|
|
||||||
message: encrypt(dataSet[vc].message)
|
|
||||||
}
|
|
||||||
compactIDB.addData("messages", {
|
|
||||||
...dm
|
|
||||||
}, `${dm.floID}|${vc}`)
|
|
||||||
_loaded.chats[dm.floID] = parseInt(vc)
|
|
||||||
compactIDB.writeData("chats", parseInt(vc), dm.floID)
|
|
||||||
dm.message = dataSet[vc].message;
|
|
||||||
newInbox.messages[vc] = dm;
|
|
||||||
addMark(dm.floID, "unread")
|
|
||||||
} else if (dataSet[vc].type === "MAIL") {
|
|
||||||
//process as mail
|
|
||||||
let data = JSON.parse(dataSet[vc].message);
|
|
||||||
let mail = {
|
|
||||||
time: dataSet[vc].time,
|
|
||||||
from: dataSet[vc].senderID,
|
|
||||||
to: [user.id],
|
|
||||||
subject: data.subject,
|
|
||||||
content: encrypt(data.content),
|
|
||||||
ref: data.ref,
|
|
||||||
prev: data.prev
|
|
||||||
}
|
|
||||||
compactIDB.addData("mails", {
|
|
||||||
...mail
|
|
||||||
}, mail.ref);
|
|
||||||
mail.content = data.content;
|
|
||||||
newInbox.mails[mail.ref] = mail;
|
|
||||||
addMark(mail.ref, "unread")
|
|
||||||
} else if (dataSet[vc].type === "CREATE_GROUP") {
|
|
||||||
//process create group
|
|
||||||
let groupInfo = JSON.parse(dataSet[vc].message);
|
|
||||||
let h = ["groupID", "created", "admin"].map(x => groupInfo[x]).join('|')
|
|
||||||
if (groupInfo.admin === dataSet[vc].senderID &&
|
|
||||||
floCrypto.verifySign(h, groupInfo.hash, groupInfo.pubKey) &&
|
|
||||||
floCrypto.getFloID(groupInfo.pubKey) === groupInfo.groupID) {
|
|
||||||
let eKey = groupInfo.eKey
|
|
||||||
groupInfo.eKey = encrypt(eKey)
|
|
||||||
compactIDB.writeData("groups", {
|
|
||||||
...groupInfo
|
|
||||||
}, groupInfo.groupID)
|
|
||||||
groupInfo.eKey = eKey
|
|
||||||
_loaded.groups[groupInfo.groupID] = groupInfo
|
|
||||||
requestGroupInbox(groupInfo.groupID)
|
|
||||||
newInbox.newgroups.push(groupInfo.groupID)
|
|
||||||
}
|
|
||||||
} else if (dataSet[vc].type === "REVOKE_KEY") {
|
|
||||||
let r = JSON.parse(dataSet[vc].message);
|
|
||||||
let groupInfo = _loaded.groups[r.groupID]
|
|
||||||
if (dataSet[vc].senderID === groupInfo.admin) {
|
|
||||||
if (typeof expiredKeys[r.groupID] !== "object")
|
|
||||||
expiredKeys[r.groupID] = {}
|
|
||||||
expiredKeys[r.groupID][vc] = groupInfo.eKey
|
|
||||||
let eKey = r.newKey
|
|
||||||
groupInfo.eKey = encrypt(eKey);
|
|
||||||
compactIDB.writeData("groups", {
|
|
||||||
...groupInfo
|
|
||||||
}, groupInfo.groupID)
|
|
||||||
groupInfo.eKey = eKey
|
|
||||||
newInbox.keyrevoke.push(groupInfo.groupID)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
//if (error !== "blocked-user")
|
//if (error !== "blocked-user")
|
||||||
console.log(error);
|
console.log(error);
|
||||||
@ -462,9 +389,9 @@
|
|||||||
const loadDataFromIDB = function(defaultList = true) {
|
const loadDataFromIDB = function(defaultList = true) {
|
||||||
return new Promise((resolve, reject) => {
|
return new Promise((resolve, reject) => {
|
||||||
if (defaultList)
|
if (defaultList)
|
||||||
dataList = ["mails", "marked", "groups", "chats", "blocked", "appendix"]
|
dataList = ["mails", "marked", "groups", "pipeline", "chats", "blocked", "appendix"]
|
||||||
else
|
else
|
||||||
dataList = ["messages", "mails", "marked", "chats", "groups", "gkeys", "blocked", "appendix"]
|
dataList = ["messages", "mails", "marked", "chats", "groups", "gkeys", "pipeline", "blocked", "appendix"]
|
||||||
let promises = []
|
let promises = []
|
||||||
for (var i = 0; i < dataList.length; i++)
|
for (var i = 0; i < dataList.length; i++)
|
||||||
promises[i] = compactIDB.readAllData(dataList[i])
|
promises[i] = compactIDB.readAllData(dataList[i])
|
||||||
@ -490,6 +417,9 @@
|
|||||||
if (dataList.includes("gkeys"))
|
if (dataList.includes("gkeys"))
|
||||||
for (let k in data.gkeys)
|
for (let k in data.gkeys)
|
||||||
data.gkeys[k] = decrypt(data.gkeys[k], AESKey);
|
data.gkeys[k] = decrypt(data.gkeys[k], AESKey);
|
||||||
|
if (dataList.includes("pipeline"))
|
||||||
|
for (let p in data.pipeline)
|
||||||
|
data.pipeline[p].eKey = decrypt(data.pipeline[p].eKey, AESKey);
|
||||||
resolve(data)
|
resolve(data)
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error(error)
|
console.error(error)
|
||||||
@ -635,6 +565,8 @@
|
|||||||
data.gkeys[k] = 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 = encrypt(data.groups[g].eKey)
|
data.groups[g].eKey = encrypt(data.groups[g].eKey)
|
||||||
|
for (let p in data.pipeline)
|
||||||
|
data.pipeline[p].eKey = encrypt(data.pipeline[p].eKey)
|
||||||
for (let c in data.chats)
|
for (let c in data.chats)
|
||||||
if (data.chats[c] <= _loaded.chats[c])
|
if (data.chats[c] <= _loaded.chats[c])
|
||||||
delete data.chats[c]
|
delete data.chats[c]
|
||||||
@ -841,6 +773,119 @@
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
processData.group = function(groupID) {
|
||||||
|
return (unparsed, newInbox) => {
|
||||||
|
if (!_loaded.groups[groupID].members.includes(unparsed.senderID))
|
||||||
|
return;
|
||||||
|
//store the pubKey if not stored already
|
||||||
|
floDapps.storePubKey(unparsed.senderID, unparsed.pubKey)
|
||||||
|
let data = {
|
||||||
|
time: unparsed.time,
|
||||||
|
sender: unparsed.senderID,
|
||||||
|
groupID: unparsed.receiverID
|
||||||
|
}
|
||||||
|
let k = _loaded.groups[groupID].eKey;
|
||||||
|
if (expiredKeys[groupID]) {
|
||||||
|
var ex = Object.keys(expiredKeys[groupID]).sort()
|
||||||
|
while (ex.length && vc > ex[0]) ex.shift()
|
||||||
|
if (ex.length)
|
||||||
|
k = expiredKeys[groupID][ex.shift()]
|
||||||
|
}
|
||||||
|
unparsed.message = decrypt(unparsed.message, k);
|
||||||
|
var infoChange = false;
|
||||||
|
if (unparsed.type === "GROUP_MSG")
|
||||||
|
data.message = encrypt(unparsed.message);
|
||||||
|
else if (data.sender === _loaded.groups[groupID].admin) {
|
||||||
|
let groupInfo = _loaded.groups[groupID]
|
||||||
|
data.admin = true;
|
||||||
|
switch (unparsed.type) {
|
||||||
|
case "ADD_MEMBERS": {
|
||||||
|
data.newMembers = unparsed.message.split("|")
|
||||||
|
data.note = unparsed.comment
|
||||||
|
groupInfo.members = [...new Set(groupInfo.members.concat(data.newMembers))]
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case "UP_DESCRIPTION": {
|
||||||
|
data.description = unparsed.message;
|
||||||
|
groupInfo.description = data.description;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case "RM_MEMBERS": {
|
||||||
|
data.rmMembers = unparsed.message.split("|")
|
||||||
|
data.note = unparsed.comment
|
||||||
|
groupInfo.members = groupInfo.members.filter(m => !data.rmMembers.includes(m))
|
||||||
|
if (data.rmMembers.includes(user.id)) {
|
||||||
|
disableGroup(groupID);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case "UP_NAME": {
|
||||||
|
data.name = unparsed.message
|
||||||
|
groupInfo.name = data.name;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
infoChange = true;
|
||||||
|
}
|
||||||
|
compactIDB.addData("messages", {
|
||||||
|
...data
|
||||||
|
}, `${groupID}|${vc}`)
|
||||||
|
if (data.message)
|
||||||
|
data.message = decrypt(data.message);
|
||||||
|
newInbox.messages[vc] = data;
|
||||||
|
if (data.sender !== user.id)
|
||||||
|
addMark(data.groupID, "unread");
|
||||||
|
return infoChange;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function requestGroupInbox(groupID) {
|
||||||
|
if (groupConnID[groupID]) { //close existing request connection (if any)
|
||||||
|
floCloudAPI.closeRequest(groupConnID[groupID]);
|
||||||
|
delete groupConnID[groupID];
|
||||||
|
}
|
||||||
|
|
||||||
|
const parseData = processData.group(groupID);
|
||||||
|
let callbackFn = function(dataSet, error) {
|
||||||
|
if (error)
|
||||||
|
return console.error(error)
|
||||||
|
console.info(dataSet)
|
||||||
|
let newInbox = {
|
||||||
|
messages: {}
|
||||||
|
}
|
||||||
|
let infoChange = false;
|
||||||
|
for (let vc in dataSet) {
|
||||||
|
if (groupID !== dataSet[vc].receiverID)
|
||||||
|
continue;
|
||||||
|
try {
|
||||||
|
infoChange = parseData(dataSet[vc], newInbox) || infoChange;
|
||||||
|
if (!_loaded.appendix[`lastReceived_${groupID}`] ||
|
||||||
|
_loaded.appendix[`lastReceived_${groupID}`] < vc)
|
||||||
|
_loaded.appendix[`lastReceived_${groupID}`] = vc;
|
||||||
|
} catch (error) {
|
||||||
|
console.log(error)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
compactIDB.writeData("appendix", _loaded.appendix[`lastReceived_${groupID}`], `lastReceived_${groupID}`);
|
||||||
|
if (infoChange) {
|
||||||
|
let newInfo = Object.assign(_loaded.groups[groupID], {});
|
||||||
|
newInfo.eKey = encrypt(newInfo.eKey)
|
||||||
|
compactIDB.writeData("groups", newInfo, groupID)
|
||||||
|
}
|
||||||
|
console.debug(newInbox);
|
||||||
|
UI.group(newInbox);
|
||||||
|
}
|
||||||
|
floCloudAPI.requestApplicationData(null, {
|
||||||
|
receiverID: groupID,
|
||||||
|
lowerVectorClock: _loaded.appendix[`lastReceived_${groupID}`] + 1,
|
||||||
|
callback: callbackFn
|
||||||
|
}).then(conn_id => groupConnID[groupID] = conn_id)
|
||||||
|
.catch(error => console.error(`request-group(${groupID}):`, error))
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
//messenger startups
|
||||||
messenger.init = function() {
|
messenger.init = function() {
|
||||||
return new Promise((resolve, reject) => {
|
return new Promise((resolve, reject) => {
|
||||||
initUserDB().then(result => {
|
initUserDB().then(result => {
|
||||||
@ -850,6 +895,7 @@
|
|||||||
//load data to memory
|
//load data to memory
|
||||||
_loaded.appendix = data.appendix;
|
_loaded.appendix = data.appendix;
|
||||||
_loaded.groups = data.groups;
|
_loaded.groups = data.groups;
|
||||||
|
_loaded.pipeline = data.pipeline;
|
||||||
_loaded.chats = data.chats;
|
_loaded.chats = data.chats;
|
||||||
_loaded.marked = data.marked;
|
_loaded.marked = data.marked;
|
||||||
_loaded.blocked = new Set(Object.keys(data.blocked));
|
_loaded.blocked = new Set(Object.keys(data.blocked));
|
||||||
@ -862,6 +908,9 @@
|
|||||||
for (let g in data.groups)
|
for (let g in data.groups)
|
||||||
if (data.groups[g].disabled !== true)
|
if (data.groups[g].disabled !== true)
|
||||||
requestGroupInbox(g);
|
requestGroupInbox(g);
|
||||||
|
for (let p in data.pipeline)
|
||||||
|
if (data.pipeline[p].disabled !== true)
|
||||||
|
requestPipelineInbox(p, data.pipeline[p].model);
|
||||||
resolve("Messenger initiated");
|
resolve("Messenger initiated");
|
||||||
}).catch(error => reject(error));
|
}).catch(error => reject(error));
|
||||||
})
|
})
|
||||||
@ -900,12 +949,13 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
//BTC multisig application
|
//BTC multisig application
|
||||||
|
const multsig = messenger.multisig = {}
|
||||||
const TYPE_BTC_MULTISIG = "btc_multisig";
|
const TYPE_BTC_MULTISIG = "btc_multisig";
|
||||||
messenger.createMultisig = function(pubKeys, minRequired) {
|
multsig.createAddress = function(pubKeys, minRequired) {
|
||||||
return new Promise(async (resolve, reject) => {
|
return new Promise(async (resolve, reject) => {
|
||||||
let receivers = pubKeys.map(p => floCrypto.getFloID(p));
|
let co_owners = pubKeys.map(p => floCrypto.getFloID(p));
|
||||||
if (receivers.includes(null))
|
if (co_owners.includes(null))
|
||||||
return reject("Invalid public key: " + pubKeys[receivers.indexOf(null)]);
|
return reject("Invalid public key: " + pubKeys[co_owners.indexOf(null)]);
|
||||||
let privateKey = await floDapps.user.private;
|
let privateKey = await floDapps.user.private;
|
||||||
let multisig = btcOperator.multiSigAddress(pubKeys, minRequired) //TODO: change to correct function
|
let multisig = btcOperator.multiSigAddress(pubKeys, minRequired) //TODO: change to correct function
|
||||||
if (typeof multisig !== 'object')
|
if (typeof multisig !== 'object')
|
||||||
@ -917,7 +967,7 @@
|
|||||||
};
|
};
|
||||||
floBlockchainAPI.writeDataMultiple([privateKey], JSON.stringify({
|
floBlockchainAPI.writeDataMultiple([privateKey], JSON.stringify({
|
||||||
[floGlobals.application]: content
|
[floGlobals.application]: content
|
||||||
}), receivers).then(txid => {
|
}), co_owners).then(txid => {
|
||||||
console.info(txid);
|
console.info(txid);
|
||||||
let key = TYPE_BTC_MULTISIG + "|" + tx.txid.substr(0, 16);
|
let key = TYPE_BTC_MULTISIG + "|" + tx.txid.substr(0, 16);
|
||||||
compactIDB.writeData("flodata", {
|
compactIDB.writeData("flodata", {
|
||||||
@ -930,7 +980,7 @@
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
messenger.listMultisig = function() {
|
multsig.listAddress = function() {
|
||||||
return new Promise((resolve, reject) => {
|
return new Promise((resolve, reject) => {
|
||||||
let options = {
|
let options = {
|
||||||
lowerKey: `${TYPE_BTC_MULTISIG}|`,
|
lowerKey: `${TYPE_BTC_MULTISIG}|`,
|
||||||
@ -961,4 +1011,160 @@
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
multsig.createTx = function(address, redeemScript, receivers, amounts) {
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
let decode = coinjs.script().decodeRedeemScript(redeemScript);
|
||||||
|
if (!decode || decode.address !== address || decode.type !== "multisig__")
|
||||||
|
return reject("Invalid redeem-script");
|
||||||
|
else if (!decode.pubKeys.includes(user.public))
|
||||||
|
return reject("User is not a part of this multisig");
|
||||||
|
else if (decode.pubKeys.length < decode.signaturesRequired)
|
||||||
|
return reject("Invalid multisig (required is greater than users)");
|
||||||
|
let co_owners = decode.pubKeys.map(p => floCrypto.getFloID(p));
|
||||||
|
let privateKey = await floDapps.user.private;
|
||||||
|
btcOperator.createMultiSigTx(address, redeemScript, receivers, amounts, null).then(tx => {
|
||||||
|
tx = btcOperator.signTx(tx, privateKey);
|
||||||
|
createPipeline(TYPE_BTC_MULTISIG, co_owners, 32).then(pipeline => {
|
||||||
|
let message = encrypt(tx, pipeline.eKey);
|
||||||
|
sendRaw(message, pipeline.id, "TRANSACTION", false)
|
||||||
|
.then(result => resolve(result))
|
||||||
|
.catch(error => reject(error))
|
||||||
|
}).catch(error => reject(error))
|
||||||
|
}).catch(error => reject(error))
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
multisig.signTx = function(pipeID, tx_hex, redeemScript) {
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
let decode = coinjs.script().decodeRedeemScript(redeemScript);
|
||||||
|
if (!decode || decode.type !== "multisig__")
|
||||||
|
return reject("Invalid redeem-script");
|
||||||
|
else if (!decode.pubKeys.includes(user.public))
|
||||||
|
return reject("User is not a part of this multisig");
|
||||||
|
let pipeline = _loaded.pipeline[pipeID],
|
||||||
|
tx = coinjs.transaction().deserialize(tx_hex);;
|
||||||
|
let privateKey = await floDapps.user.private;
|
||||||
|
tx_hex = btcOperator.signTx(tx, privateKey);
|
||||||
|
let message = encrypt(tx_hex, pipeline.eKey);
|
||||||
|
sendRaw(message, pipeline.id, "TRANSACTION", false).then(result => {
|
||||||
|
if (!__Enough_signs_collected(tx)) //TODO
|
||||||
|
return resolve(tx_hex);
|
||||||
|
__Arranged_signatures_if_needed(tx) //TODO
|
||||||
|
btcOperator.broadcast(tx_hex).then(result => {
|
||||||
|
let txid = result.txid
|
||||||
|
sendRaw(encrypt(txid, pipeline.eKey), pipeline.id, "BROADCAST", false)
|
||||||
|
.then(result => resolve(txid))
|
||||||
|
.catch(error => reject(error))
|
||||||
|
}).catch(error => reject(error))
|
||||||
|
}).catch(error => reject(error))
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
//Pipelines
|
||||||
|
const createPipeline = function(model, members, ekeySize = 16) {
|
||||||
|
//validate members
|
||||||
|
let imem1 = [],
|
||||||
|
imem2 = []
|
||||||
|
members.forEach(m =>
|
||||||
|
!floCrypto.validateAddr(m) ? imem1.push(m) :
|
||||||
|
m in floGlobals.pubKeys ? null : imem2.push(m)
|
||||||
|
);
|
||||||
|
if (imem1.length)
|
||||||
|
return reject(`Invalid Members(floIDs): ${imem1}`)
|
||||||
|
else if (imem2.length)
|
||||||
|
return reject(`Invalid Members (pubKey not available): ${imem2}`)
|
||||||
|
//create pipeline info
|
||||||
|
const id = floCrypto.tmpID;
|
||||||
|
let pipeline = {
|
||||||
|
id,
|
||||||
|
model,
|
||||||
|
members
|
||||||
|
}
|
||||||
|
if (ekeySize)
|
||||||
|
pipeline.eKey = floCrypto.randString(ekeySize);
|
||||||
|
//send pipeline info to members
|
||||||
|
let pipelineInfo = JSON.stringify(pipeline);
|
||||||
|
let promises = members.map(m => sendRaw(pipelineInfo, m, "CREATE_PIPELINE", true));
|
||||||
|
Promise.allSettled(promises).then(results => {
|
||||||
|
console.debug(results.filter(r => r.status = "rejected").map(r => r.reason));
|
||||||
|
_loaded.pipeline[pipeline.id] = Object.assign(pipeline, {});
|
||||||
|
if (pipeline.eKey)
|
||||||
|
pipeline.eKey = encrypt(pipeline.eKey);
|
||||||
|
compactIDB.addData("pipeline", pipeline, pipeline.id).then(result => {
|
||||||
|
requestPipelineInbox(pipeline.id, pipeline.model);
|
||||||
|
resolve(_loaded.pipeline[pipeline.id])
|
||||||
|
}).catch(error => reject(error))
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
function requestPipelineInbox(pipeID, model) {
|
||||||
|
if (pipeConnID[pipeID]) { //close existing request connection (if any)
|
||||||
|
floCloudAPI.closeRequest(pipeConnID[pipeID]);
|
||||||
|
delete pipeConnID[pipeID];
|
||||||
|
}
|
||||||
|
|
||||||
|
let parseData = processData.pipeline[model](pipeID);
|
||||||
|
let callbackFn = function(dataSet, error) {
|
||||||
|
if (error)
|
||||||
|
return console.error(error);
|
||||||
|
console.info(dataSet)
|
||||||
|
let newInbox = {
|
||||||
|
messages: {}
|
||||||
|
}
|
||||||
|
for (let vc in dataSet) {
|
||||||
|
if (pipeID !== dataSet[vc].receiverID)
|
||||||
|
continue;
|
||||||
|
try {
|
||||||
|
parseData(dataSet[vc], newInbox);
|
||||||
|
if (data.sender !== user.id)
|
||||||
|
addMark(pipeID, "unread")
|
||||||
|
if (!_loaded.appendix[`lastReceived_${pipeID}`] ||
|
||||||
|
_loaded.appendix[`lastReceived_${pipeID}`] < vc)
|
||||||
|
_loaded.appendix[`lastReceived_${pipeID}`] = vc;
|
||||||
|
} catch (error) {
|
||||||
|
console.log(error)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
compactIDB.writeData("appendix", _loaded.appendix[`lastReceived_${pipeID}`], `lastReceived_${pipeID}`);
|
||||||
|
console.debug(newInbox);
|
||||||
|
UI.pipeline(model, newInbox);
|
||||||
|
}
|
||||||
|
|
||||||
|
floCloudAPI.requestApplicationData(null, {
|
||||||
|
receiverID: pipeID,
|
||||||
|
lowerVectorClock: _loaded.appendix[`lastReceived_${pipeID}`] + 1,
|
||||||
|
callback: callbackFn
|
||||||
|
}).then(conn_id => pipeConnID[pipeID] = conn_id)
|
||||||
|
.catch(error => console.error(`request-pipeline(${pipeID}):`, error))
|
||||||
|
}
|
||||||
|
|
||||||
|
processData.pipeline = {};
|
||||||
|
processData.pipeline[TYPE_BTC_MULTISIG] = function(pipeID) {
|
||||||
|
return (unparsed) => {
|
||||||
|
if (!_loaded.pipeline[pipeID].members.includes(floCrypto.toFloID(unparsed.senderID)))
|
||||||
|
return;
|
||||||
|
let data = {
|
||||||
|
time: unparsed.time,
|
||||||
|
sender: unparsed.senderID,
|
||||||
|
pipeID: unparsed.receiverID
|
||||||
|
}
|
||||||
|
let k = _loaded.pipeline[pipeID].eKey;
|
||||||
|
unparsed.message = decrypt(unparsed.message, k)
|
||||||
|
//store the pubKey if not stored already
|
||||||
|
floDapps.storePubKey(unparsed.senderID, unparsed.pubKey);
|
||||||
|
if (unparsed.type === "TRANSACTION") {
|
||||||
|
data.message = encrypt(unparsed.message);
|
||||||
|
} else if (unparsed.type === "BROADCAST") {
|
||||||
|
data.txid = unparsed.message;
|
||||||
|
//TODO: check if txid is valid (and confirmed?) and close the pipeline connection
|
||||||
|
}
|
||||||
|
compactIDB.addData("messages", {
|
||||||
|
...data
|
||||||
|
}, `${pipeID}|${vc}`);
|
||||||
|
if (data.message)
|
||||||
|
data.message = decrypt(data.message);
|
||||||
|
newInbox.messages[vc] = data;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
})();
|
})();
|
||||||
Loading…
Reference in New Issue
Block a user