diff --git a/src/backup/intra.js b/src/backup/intra.js index 2c4965c..bf27125 100644 --- a/src/backup/intra.js +++ b/src/backup/intra.js @@ -143,6 +143,8 @@ function processTaskFromPrevNode(packet) { orderBackup(task.order); break; case TYPE_.STORE_BACKUP_DATA: storeBackupData(task.data, from, packet); break; + case TYPE_.EDIT_BACKUP_DATA: + editBackupData(task.data, from, packet); break; case TYPE_.TAG_BACKUP_DATA: tagBackupData(task.data, from, packet); break; case TYPE_.NOTE_BACKUP_DATA: @@ -266,7 +268,7 @@ function reconnectNextNode() { //Case: No other node is online console.info(error); //close prev node connection if inactive - if(_prevNode.id) + if (_prevNode.id) _prevNode.close(); //Serve all nodes for (let sn in floGlobals.supernodes) @@ -318,6 +320,16 @@ function storeBackupData(data, from, packet) { }; }; +//Edit (backup) data +function editBackupData(data, from, packet) { + let closestNode = cloud.closestNode(data.receiverID); + if (_list.stored.includes(closestNode)) { + DB.storeEdit(closestNode, data).then(_ => null).catch(e => console.error(e)); + if (_list[closestNode] < floGlobals.sn_config.backupDepth && _nextNode.id !== from) + _nextNode.send(packet); + }; +}; + //Tag (backup) data function tagBackupData(data, from, packet) { let closestNode = cloud.closestNode(data.receiverID); @@ -369,6 +381,7 @@ function forwardToNextNode(mode, data) { var modeMap = { 'TAG': TYPE_.TAG_BACKUP_DATA, 'NOTE': TYPE_.NOTE_BACKUP_DATA, + 'EDIT': TYPE_.EDIT_BACKUP_DATA, 'DATA': TYPE_.STORE_BACKUP_DATA }; if (mode in modeMap && _nextNode.id) diff --git a/src/client.js b/src/client.js index 08cee39..5e39b26 100644 --- a/src/client.js +++ b/src/client.js @@ -15,19 +15,19 @@ function processIncomingData(data) { return reject(INVALID("Invalid Time")); else { let process; - if ('request' in data) //Request + if ('request' in data) //Request process = processRequestFromUser(data.request); else if ('message' in data) //Store data process = processDataFromUser(data); - else if ('tag' in data) //Tag data + else if ('tag' in data) //Tag data (tags are added by subAdmins/TrustedIDs) process = processTagFromUser(data); - else if ('note' in data) + else if ('note' in data) //Note data (notes are added by receiver) process = processNoteFromUser(data); + else if ('edit' in data) //Comment can be edited by sender anytime with new sign + return processEditFromUser(data); /* - else if (data.edit) - return processEditFromUser(gid, uid, data); - else if (data.delete) - return processDeleteFromUser(gid, uid, data); + else if ('delete' in data) + return processDeleteFromUser(data); */ else return reject(INVALID("Invalid Data-format")); @@ -90,6 +90,37 @@ function processRequestFromUser(request) { }); }; +function processEditFromUser(data) { + return new Promise((resolve, reject) => { + if (!floCrypto.validateAddr(data.receiverID)) + return reject(INVALID("Invalid receiverID")); + let closeNode = cloud.closestNode(data.receiverID); + if (!_list.serving.includes(closeNode)) + return reject(INVALID("Incorrect Supernode")); + DB.getData(closeNode, data.vectorClock).then(result => { + if (!result.length) + return reject(INVALID("Invalid vectorClock")); + result = result[0]; + if (result.senderID !== data.requestorID) + return reject(INVALID("Invalid requestorID")); + if (!floCrypto.verifyPubKey(data.pubKey, data.requestorID)) + return reject(INVALID("Invalid pubKey")); + let tmp_data = result; + tmp_data.comment = data.edit; //edited comment data + let hashcontent = ["receiverID", "time", "application", "type", "message", "comment"] + .map(d => tmp_data[d]).join("|"); + if (!floCrypto.verifySign(hashcontent, data.sign, data.pubKey)) + return reject(INVALID("Invalid signature")); + let comment_edit = ([null].includes(data.edit) ? null : data.note.toString()); //if value is null, then comment will be removed (ie, NULL value in SQL) + DB.editData(closeNode, data.vectorClock, comment_edit, data.sign).then(rb => { + DB.getData(closeNode, data.vectorClock) + .then(result => resolve([result[0], 'EDIT', rb])) + .catch(error => reject(error)) + }).catch(error => reject(error)) + }).catch(error => reject(error)) + }) +} + function processTagFromUser(data) { return new Promise((resolve, reject) => { if (!floCrypto.validateAddr(data.receiverID)) diff --git a/src/database.js b/src/database.js index 8ebad3c..4bb0634 100644 --- a/src/database.js +++ b/src/database.js @@ -275,6 +275,25 @@ DB.addData = function (snID, data) { }); }; +DB.editData = function (snID, vectorClock, comment, newSign) { + return new Promise((resolve, reject) => { + let data = { + [B_struct.COMMENT]: comment, + [B_struct.SIGNATURE]: newSign, + [L_struct.LOG_TIME]: Date.now() + }; + let attr = Object.keys(data); + let values = attr.map(a => data[a]).concat(vectorClock); + data[H_struct.VECTOR_CLOCK] = vectorClock; //also add vectorClock to resolve data + let statement = "UPDATE _" + snID + + " SET " + attr.map(a => a + "=?").join(", ") + + " WHERE " + H_struct.VECTOR_CLOCK + "=?"; + queryResolve(statement, values) + .then(result => resolve(data)) + .catch(error => reject(error)); + }) +}; + DB.getData = function (snID, vectorClock) { return new Promise((resolve, reject) => { let statement = "SELECT * FROM _" + snID + @@ -325,7 +344,7 @@ DB.noteData = function (snID, vectorClock, note, noteTime, noteKey, noteSign) { .then(result => resolve(data)) .catch(error => reject(error)); }); -} +}; DB.searchData = function (snID, request) { return new Promise((resolve, reject) => { @@ -440,6 +459,18 @@ DB.storeData = function (snID, data, updateLogTime = false) { }); }; +DB.storeEdit = function (snID, data) { + let attr = [B_struct.COMMENT, B_struct.SIGNATURE, L_struct.LOG_TIME]; + let values = attr.map(a => data[a]).concat(data[H_struct.VECTOR_CLOCK]); + let statement = "UPDATE _" + snID + + " SET " + attr.map(a => a + "=?").join(", ") + + " WHERE " + H_struct.VECTOR_CLOCK + "=?"; + queryResolve(statement, values) + .then(result => resolve(data)) + .catch(error => reject(error)); + +}; + DB.storeTag = function (snID, data) { return new Promise((resolve, reject) => { let attr = Object.keys(T_struct).map(a => T_struct[a]).concat(L_struct.LOG_TIME); @@ -464,7 +495,7 @@ DB.storeNote = function (snID, data) { .then(result => resolve(data)) .catch(error => reject(error)); }) -} +}; DB.deleteData = function (snID, vectorClock) { return new Promise((resolve, reject) => { diff --git a/src/server.js b/src/server.js index 999432c..ce621e7 100644 --- a/src/server.js +++ b/src/server.js @@ -38,7 +38,7 @@ module.exports = function Server(port) { res.end(JSON.stringify(result[0])); //result[0] = full data if (result[1]) { //result[1] = mode (ie: DATA/TAG/NOTE) refresher.countdown; - if (['DATA', 'TAG', 'NOTE'].includes(result[1])) + if (['DATA', 'EDIT', 'TAG', 'NOTE'].includes(result[1])) sendToLiveRequests(result[0]); intra.forwardToNextNode(result[1], result[0]); };