Default cashier and other changes

- Encrypt UPI ID of users before sending to cashier
- Cashier: reconnect status ws at a regular interval to avoid timeout
- return the default cashier ID if no cashier is online (configured via blockchain)
This commit is contained in:
sairajzero 2022-05-24 01:54:04 +05:30
parent 7760570c95
commit 6c17afb913
2 changed files with 97 additions and 59 deletions

View File

@ -4,12 +4,13 @@ const TYPE_MONEY_REQUEST = "MoneyRequests",
TYPE_CASHIER_UPI = "CashierUPI";
const cashierUPI = {};
const cashierPubKeys = {};
//For regular users
const User = {};
const cashierStatus = {};
User.init = function () {
User.init = function() {
return new Promise((resolve, reject) => {
let promises;
//Request cashier for token-cash exchange
@ -55,22 +56,24 @@ User.init = function () {
})
}
User.getCashierUPI = function () {
User.getCashierUPI = function() {
return new Promise((resolve) => {
Promise.allSettled(floGlobals.subAdmins.map(cashierID => floCloudAPI.requestApplicationData(TYPE_CASHIER_UPI, {
senderID: cashierID,
mostRecent: true
}))).then(result => {
for (let r of result)
if (r.status === "fulfilled" && r.value.length)
if (r.status === "fulfilled" && r.value.length) {
cashierUPI[r.value[0].senderID] = floCloudAPI.util.decodeMessage(r.value[0].message).upi;
cashierPubKeys[r.value[0].senderID] = r.value[0].pubKey; //get pubKey of cashier from messages for encryption
}
resolve(cashierUPI);
})
})
}
Object.defineProperty(User, 'cashierRequests', {
get: function () {
get: function() {
let fk = floCloudAPI.util.filterKey(TYPE_CASHIER_REQUEST, {
senderID: myFloID,
group: "Cashiers",
@ -80,7 +83,7 @@ Object.defineProperty(User, 'cashierRequests', {
});
Object.defineProperty(User, 'moneyRequests', {
get: function () {
get: function() {
let fk = floCloudAPI.util.filterKey(TYPE_MONEY_REQUEST, {
receiverID: myFloID,
});
@ -88,84 +91,110 @@ Object.defineProperty(User, 'moneyRequests', {
}
});
User.findCashier = function () {
User.findCashier = function() {
let online = [];
for (let c in cashierStatus)
if (cashierStatus[c] && cashierUPI[c])
online.push(c);
if (!online.length)
return null;
else {
if (!online.length) {
if (floGlobals.settings.defaultCashier && floGlobals.settings.defaultCashier in cashierUPI)
return floGlobals.settings.defaultCashier;
else
return null;
} else {
const random = floCrypto.randInt(0, online.length - 1)
return online[random];
}
}
User.cashToToken = function (cashier, amount, upiTxID) {
User.cashToToken = function(cashier, amount, upiTxID) {
return new Promise((resolve, reject) => {
if (!floGlobals.subAdmins.includes(cashier))
return reject("Invalid cashier");
floCloudAPI.sendGeneralData({
mode: "cash-to-token",
amount: amount,
upi_txid: upiTxID
}, TYPE_CASHIER_REQUEST, {
receiverID: cashier
}).then(result => resolve(result))
mode: "cash-to-token",
amount: amount,
upi_txid: upiTxID
}, TYPE_CASHIER_REQUEST, {
receiverID: cashier
}).then(result => resolve(result))
.catch(error => reject(error))
})
}
User.tokenToCash = function (cashier, amount, blkTxID, upiID) {
User.tokenToCash = function(cashier, amount, blkTxID, upiID) {
return new Promise((resolve, reject) => {
if (!floGlobals.subAdmins.includes(cashier))
return reject("Invalid cashier");
floCloudAPI.sendGeneralData({
mode: "token-to-cash",
amount: amount,
token_txid: blkTxID,
upi_id: upiID
}, TYPE_CASHIER_REQUEST, {
receiverID: cashier
}).then(result => resolve(result))
mode: "token-to-cash",
amount: amount,
token_txid: blkTxID,
upi_id: floCrypto.encryptData(upiID, cashierPubKeys[cashier])
}, TYPE_CASHIER_REQUEST, {
receiverID: cashier
}).then(result => resolve(result))
.catch(error => reject(error))
})
}
User.sendToken = function (receiverID, amount, remark = '') {
User.sendToken = function(receiverID, amount, remark = '') {
return new Promise((resolve, reject) => {
tokenAPI.sendToken(myPrivKey, amount, receiverID, remark)
floTokenAPI.sendToken(myPrivKey, amount, receiverID, remark)
.then(result => resolve(result))
.catch(error => reject(error))
})
}
User.requestToken = function (floID, amount, remark = '') {
User.requestToken = function(floID, amount, remark = '') {
return new Promise((resolve, reject) => {
floCloudAPI.sendGeneralData({
amount: amount,
remark: remark
}, TYPE_MONEY_REQUEST, {
receiverID: floID
}).then(result => resolve(result))
amount: amount,
remark: remark
}, TYPE_MONEY_REQUEST, {
receiverID: floID
}).then(result => resolve(result))
.catch(error => reject(error))
})
}
User.decideRequest = function (request, note) {
User.decideRequest = function(request, note) {
return new Promise((resolve, reject) => {
floCloudAPI.noteApplicationData(request.vectorClock, note, {
receiverID: myFloID
}).then(result => resolve(result))
receiverID: myFloID
}).then(result => resolve(result))
.catch(error => reject(error))
})
}
const Cashier = {};
Cashier.init = function () {
var status_conn_id = null;
function statusReconnect() {
if (status_conn_id) {
floCloudAPI.closeRequest(status_conn_id)
status_conn_id = null;
}
floCloudAPI.setStatus()
.then(result => status_conn_id = result)
.catch(error => console.error(error))
}
var status_interval_instance = null;
function startStatusInterval() {
if (status_interval_instance) {
clearInterval(status_interval_instance);
status_interval_instance = null;
}
statusReconnect();
status_interval_instance = setInterval(statusReconnect, 15 * 60 * 1000);
}
Cashier.init = function() {
delegate(getRef('cashier_pending_request_list'), 'click', '.process-cashier-request', e => {
const requestID = e.delegateTarget.closest('.cashier-request').dataset.vc;
const requestID = e.delegateTarget.closest('.cashier-request').id;
cashierUI.completeRequest(requestID)
})
getRef('cashier_requests_selector').addEventListener('change', e => {
@ -179,31 +208,32 @@ Cashier.init = function () {
callback: cashierUI.renderRequests //UI_fn
}));
//Set online status of cashier(self)
promises.push(floCloudAPI.setStatus());
//promises.push(floCloudAPI.setStatus());
/*
promises.push(floCloudAPI.requestObjectData("UPI", { //Is this needed?
callback: UI_RENDER_FN
}));
*/
promises.push(User.getCashierUPI());
Promise.all(promises)
.then(result => resolve(result))
.catch(error => reject(error))
Promise.all(promises).then(result => {
startStatusInterval(); //Set online status of cashier(self) [connection refreshes on interval]
resolve(result)
}).catch(error => reject(error));
})
}
Cashier.updateUPI = function (upi_id) {
Cashier.updateUPI = function(upi_id) {
return new Promise((resolve, reject) => {
floCloudAPI.sendApplicationData({
upi: upi_id
}, TYPE_CASHIER_UPI)
upi: upi_id
}, TYPE_CASHIER_UPI)
.then(result => resolve(result))
.catch(error => reject(error))
})
}
Object.defineProperty(Cashier, 'Requests', {
get: function () {
get: function() {
let fk = floCloudAPI.util.filterKey(TYPE_CASHIER_REQUEST, {
receiverID: myFloID
});
@ -212,29 +242,29 @@ Object.defineProperty(Cashier, 'Requests', {
}
});
Cashier.finishRequest = function (request, txid) {
Cashier.finishRequest = function(request, txid) {
return new Promise((resolve, reject) => {
floCloudAPI.tagApplicationData(request.vectorClock, 'COMPLETED', {
receiverID: myFloID
}).then(result => {
floCloudAPI.noteApplicationData(request.vectorClock, txid, {
receiverID: myFloID
}).then(result => resolve(result))
receiverID: myFloID
}).then(result => resolve(result))
.catch(error => reject(error))
}).catch(error => reject(error))
})
}
Cashier.rejectRequest = function (request, reason) {
Cashier.rejectRequest = function(request, reason) {
return new Promise((resolve, reject) => {
floCloudAPI.noteApplicationData(request.vectorClock, "REJECTED:" + reason, {
receiverID: myFloID
}).then(result => resolve(result))
receiverID: myFloID
}).then(result => resolve(result))
.catch(error => reject(error))
})
}
Cashier.checkIfUpiTxIsValid = function (upiTxID) {
Cashier.checkIfUpiTxIsValid = function(upiTxID) {
return new Promise((resolve, reject) => {
let requests = Cashier.Requests;
for (let r in requests)
@ -245,15 +275,15 @@ Cashier.checkIfUpiTxIsValid = function (upiTxID) {
})
}
Cashier.checkIfTokenTxIsValid = function (tokenTxID, sender, amount) {
Cashier.checkIfTokenTxIsValid = function(tokenTxID, sender, amount) {
return new Promise((resolve, reject) => {
let requests = Cashier.Requests;
for (let r in requests)
if (requests[r].message.mode === "token-to-cash" && requests[r].note)
if (requests[r].message.token_txid === tokenTxID)
return reject([true, "Token transaction is already used for another request"]);
tokenAPI.getTx(tokenTxID).then(tx => {
let parsedTxData = tokenAPI.util.parseTxData(tx);
floTokenAPI.getTx(tokenTxID).then(tx => {
let parsedTxData = floTokenAPI.util.parseTxData(tx);
console.debug(parsedTxData);
if (parsedTxData.type !== "transfer" || parsedTxData.transferType !== "token")
reject([true, "Invalid token transfer type"]);

View File

@ -409,6 +409,14 @@ function declineTopUp() {
function completeTokenToCashRequest(request) {
const { vectorClock, senderID, message: { token_txid, amount, upi_id } } = request
if (upi_id instanceof Object && "secret" in upi_id){
try {
upi_id = floCrypto.decryptData(upi_id, myPrivKey);
} catch(error) {
console.error("UPI ID is not encrypted with a proper key", error);
return notify("Invalid UPI ID", 'error');
}
}
Cashier.checkIfTokenTxIsValid(token_txid, senderID, amount).then(result => {
getPromptInput('Process', `Token transfer is verified!\n Send ${formatAmount(amount)}\n to ${upi_id}\n Enter UPI transaction ID`, {
placeholder: 'UPI transaction ID',
@ -550,7 +558,7 @@ const render = {
return clone;
},
transactionMessage(details) {
const { tokenAmount, time, sender, receiver, flodata } = tokenAPI.util.parseTxData(details)
const { tokenAmount, time, sender, receiver, flodata } = floTokenAPI.util.parseTxData(details)
let messageType = sender === receiver ? 'self' : sender === myFloID ? 'sent' : 'received';
const clone = getRef('transaction_message_template').content.cloneNode(true).firstElementChild;
clone.classList.add(messageType);
@ -585,10 +593,10 @@ const render = {
if (paymentsHistoryLoader)
paymentsHistoryLoader.clear()
getRef('payments_history').innerHTML = '<sm-spinner></sm-spinner>';
tokenAPI.getAllTxs(myFloID).then(({ transactions }) => {
floTokenAPI.getAllTxs(myFloID).then(({ transactions }) => {
for (const transactionId in transactions) {
paymentTransactions.push({
...tokenAPI.util.parseTxData(transactions[transactionId]),
...floTokenAPI.util.parseTxData(transactions[transactionId]),
txid: transactionId
})
}
@ -647,7 +655,7 @@ function buttonLoader(id, show) {
function refreshBalance(button) {
if (button)
buttonLoader(button, true)
tokenAPI.getBalance(myFloID).then((balance = 0) => {
floTokenAPI.getBalance(myFloID).then((balance = 0) => {
const [beforeDecimal, afterDecimal] = formatAmount(balance).split('₹')[1].split('.')
getRef('rupee_balance').innerHTML = `<span><b>${beforeDecimal}</b></span>.<span>${afterDecimal}</span>`
if (button)