API(admin): generate, reshare and discard sinks

- generateSink: generates a sinkID for given group
- reshareSink: regenerate the shares for given id and distribute
- discardSink: discards the given sink id

Note: All these APIs are admin-only
This commit is contained in:
sairajzero 2022-11-15 05:14:25 +05:30
parent c8b70e3fec
commit c5b43291ab
5 changed files with 231 additions and 8 deletions

View File

@ -519,6 +519,7 @@
DUPLICATE_SIGNATURE: '017',
SESSION_INVALID: '018',
SESSION_EXPIRED: '019',
INVALID_VALUE: '020',
INVALID_TOKEN_NAME: '021',
INVALID_NUMBER: '022',
INVALID_TYPE: '023',
@ -610,7 +611,7 @@
exchangeAPI.getSink = function (service = serviceList.EXCHANGE) {
return new Promise((resolve, reject) => {
if (!(service in serviceList))
return reject(ExchangeError(ExchangeError.BAD_REQUEST_CODE, 'service required', errorCode.INVALID_TYPE));
return reject(ExchangeError(ExchangeError.BAD_REQUEST_CODE, 'service required', errorCode.INVALID_VALUE));
fetch_api('/get-sink?service=' + service)
.then(result => {
responseParse(result, false)
@ -1557,6 +1558,99 @@
})
}
exchangeAPI.generateSink = function (group, floID, privKey) {
if (!floCrypto.verifyPrivKey(privKey, floID))
return reject(ExchangeError(ExchangeError.BAD_REQUEST_CODE, "Invalid Private Key", errorCode.INVALID_PRIVATE_KEY));
if (floID !== DEFAULT.marketID)
return reject(ExchangeError(ExchangeError.BAD_REQUEST_CODE, "Access Denied", errorCode.ACCESS_DENIED));
let request = {
floID: floID,
group: group,
timestamp: Date.now()
};
request.pubKey = floCrypto.getPubKeyHex(privKey);
request.sign = signRequest({
type: "generate_sink",
group: group,
timestamp: request.timestamp
}, privKey);
console.debug(request);
fetch_api('/generate-sink', {
method: "POST",
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify(request)
}).then(result => {
responseParse(result, false)
.then(result => resolve(result))
.catch(error => reject(error))
}).catch(error => reject(error))
}
exchangeAPI.reshareSink = function (sinkID, floID, privKey) {
if (!floCrypto.verifyPrivKey(privKey, floID))
return reject(ExchangeError(ExchangeError.BAD_REQUEST_CODE, "Invalid Private Key", errorCode.INVALID_PRIVATE_KEY));
if (floID !== DEFAULT.marketID)
return reject(ExchangeError(ExchangeError.BAD_REQUEST_CODE, "Access Denied", errorCode.ACCESS_DENIED));
let request = {
floID: floID,
id: sinkID,
timestamp: Date.now()
};
request.pubKey = floCrypto.getPubKeyHex(privKey);
request.sign = signRequest({
type: "reshare_sink",
id: sinkID,
timestamp: request.timestamp
}, privKey);
console.debug(request);
fetch_api('/reshare-sink', {
method: "POST",
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify(request)
}).then(result => {
responseParse(result, false)
.then(result => resolve(result))
.catch(error => reject(error))
}).catch(error => reject(error))
}
exchangeAPI.discardSink = function (sinkID, floID, privKey) {
if (!floCrypto.verifyPrivKey(privKey, floID))
return reject(ExchangeError(ExchangeError.BAD_REQUEST_CODE, "Invalid Private Key", errorCode.INVALID_PRIVATE_KEY));
if (floID !== DEFAULT.marketID)
return reject(ExchangeError(ExchangeError.BAD_REQUEST_CODE, "Access Denied", errorCode.ACCESS_DENIED));
let request = {
floID: floID,
id: sinkID,
timestamp: Date.now()
};
request.pubKey = floCrypto.getPubKeyHex(privKey);
request.sign = signRequest({
type: "discard_sink",
id: sinkID,
timestamp: request.timestamp
}, privKey);
console.debug(request);
fetch_api('/discard-sink', {
method: "POST",
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify(request)
}).then(result => {
responseParse(result, false)
.then(result => resolve(result))
.catch(error => reject(error))
}).catch(error => reject(error))
}
exchangeAPI.init = function refreshDataFromBlockchain() {
return new Promise((resolve, reject) => {
let nodes, assets, tags, lastTx;

View File

@ -88,6 +88,11 @@ module.exports = function App(secret) {
app.post('/withdraw-token', Request.WithdrawToken);
app.post('/get-transact', Request.GetUserTransacts);
//generate or discard sinks (admin only)
app.post('/generate-sink', Request.GenerateSink);
app.post('/reshare-sink', Request.DiscardSink);
app.post('/discard-sink', Request.DiscardSink);
//convert from or to coin
app.get('/get-convert-values', Request.GetConvertValues);
app.post('/convert-to', Request.ConvertTo);

View File

@ -218,11 +218,8 @@ function informLiveNodes(init) {
} else if (!flag) {
console.log("Starting the exchange...");
//generate a sinkID for each group in starting list
keys.sink_groups.generate_list.forEach(group => {
let newSink = floCrypto.generateNewID();
console.debug("Generated sink:", group, newSink.floID);
sendSharesToNodes(newSink.floID, group, generateShares(newSink.privKey));
})
keys.sink_groups.initial_list.forEach(group =>
generateSink(group).then(_ => null).catch(e => console.error(e)));
}
}).catch(error => console.error(error));
});
@ -276,6 +273,63 @@ function slaveConnect(floID, pubKey, ws, sinks) {
}
}
const eCode = require('../docs/scripts/floExchangeAPI').errorCode;
function generateSink(group) {
return new Promise((resolve, reject) => {
if (!keys.sink_groups.generate_list.includes(group))
return reject(INVALID(eCode.INVALID_VALUE, `Invalid Group ${group}`));
try {
let newSink = floCrypto.generateNewID();
console.debug("Generated sink:", group, newSink.floID);
sendSharesToNodes(newSink.floID, group, generateShares(newSink.privKey));
resolve(`Generated ${newSink.floID} (${group})`);
} catch (error) {
reject(error)
}
})
}
function reshareSink(id) {
return new Promise((resolve, reject) => {
if (!floCrypto.validateAddr(data.id))
return reject(INVALID(eCode.INVALID_VALUE, `Invalid ID ${id}`));
else {
let group = keys.sink_chest.find_group(id);
if (!group)
return reject(INVALID(eCode.NOT_FOUND, `ID ${id} not found`));
else keys.checkIfDiscarded(id).then(result => {
if (result)
return reject(INVALID(eCode.NOT_FOUND, `ID is discarded`));
try {
reconstructShares(group, id);
resolve(`Resharing ${id} (${group})`);
} catch (error) {
reject(error);
}
}).catch(error => reject(error))
}
})
}
function discardSink(id) {
return new Promise((resolve, reject) => {
if (!floCrypto.validateAddr(data.id))
return reject(INVALID(eCode.INVALID_VALUE, `Invalid ID ${id}`));
else if (!keys.sink_chest.find_group(id))
return reject(INVALID(eCode.NOT_FOUND, `ID ${id} not found`));
else keys.checkIfDiscarded(id).then(result => {
if (result)
return reject(INVALID(eCode.DUPLICATE_ENTRY, `ID already discarded`));
keys.discardSink(id).then(result => {
console.debug("Discarded sink:", id);
resolve(result);
}).catch(error => reject(error))
}).catch(error => reject(error))
})
}
function checkForDiscardedSinks() {
let cur_time = Date.now(),
all_sinks = keys.sink_chest.get_all();
@ -401,6 +455,11 @@ function initProcess(app) {
module.exports = {
init: initProcess,
collectAndCall,
sink: {
generate: generateSink,
reshare: reshareSink,
discard: discardSink
},
set nodeList(list) {
nodeURL = list;
nodeKBucket = new K_Bucket(floGlobals.adminID, Object.keys(nodeURL));

View File

@ -289,14 +289,25 @@ function checkIfDiscarded(id) {
})
}
function discardSink(id) {
return new Promise((resolve, reject) => {
DB.query("INSERT INTO discardedSinks(floID) VALUE (?)", [id])
.then(result => resolve(`Discarded ${id}`))
.catch(error => reject(error))
})
}
//Sink groups and chest
const sink_groups = {
get EXCHANGE() { return "exchange" },
get CONVERT() { return "convert" },
get BLOCKCHAIN_BONDS() { return "blockchain_bonds" },
get BOBS_FUND() { return "bobs_fund" },
get generate_list() { //list to generate when starting exchange
get initial_list() { //list to generate when starting exchange
return [this.EXCHANGE, this.CONVERT]
},
get generate_list() { //list allowed to generate
return [this.EXCHANGE, this.CONVERT, this.BLOCKCHAIN_BONDS, this.BOBS_FUND]
}
};
@ -343,6 +354,14 @@ const sink_ids = {}, sink_chest = {
i = floCrypto.randInt(0, ids.length);
return ids[i];
},
find_group(id) {
let group = null;
for (let g in sink_ids)
if (id in sink_ids[g]) {
group = g; break;
}
return group;
},
get_all() {
let ids = {};
for (let g in sink_ids)
@ -359,6 +378,7 @@ module.exports = {
getStoredList,
getDiscardedList,
checkIfDiscarded,
discardSink,
set node_priv(key) {
_.node_priv = key;
},

View File

@ -6,6 +6,7 @@ const conversion = require('./services/conversion');
const blockchain_bonds = require("./services/bonds");
const bobs_fund = require("./services/bobs-fund");
const background = require("./background");
const sink = require("./backup/head").sink;
const keys = require("./keys");
const {
@ -307,6 +308,47 @@ function RemoveDistributor(req, res) {
}, () => market.removeDistributor(data.distributor, data.asset));
}
function GenerateSink(req, res) {
let data = req.body;
if (data.floID !== floGlobals.adminID)
res.status(INVALID.e_code).send(INVALID.str(eCode.ACCESS_DENIED, "Access Denied"));
else if (!data.pubKey)
res.status(INVALID.e_code).send(INVALID.str(eCode.MISSING_PARAMETER, "Public key missing"));
else processRequest(res, data.floID, data.pubKey, data.sign, "Generate Sink", {
type: "generate_sink",
group: data.group,
timestamp: data.timestamp
}, () => sink.generate(group));
}
function ReshareSink(req, res) {
let data = req.body;
if (data.floID !== floGlobals.adminID)
res.status(INVALID.e_code).send(INVALID.str(eCode.ACCESS_DENIED, "Access Denied"));
else if (!data.pubKey)
res.status(INVALID.e_code).send(INVALID.str(eCode.MISSING_PARAMETER, "Public key missing"));
else if (!floCrypto.validateAddr(data.id))
res.status(INVALID.e_code).send(INVALID.str(eCode.INVALID_VALUE, `Invalid ID ${data.id}`));
else processRequest(res, data.floID, data.pubKey, data.sign, "Reshare Sink", {
type: "reshare_sink",
id: data.id,
timestamp: data.timestamp
}, () => sink.reshare(id));
}
function DiscardSink(req, res) {
let data = req.body;
if (data.floID !== floGlobals.adminID)
res.status(INVALID.e_code).send(INVALID.str(eCode.ACCESS_DENIED, "Access Denied"));
else if (!data.pubKey)
res.status(INVALID.e_code).send(INVALID.str(eCode.MISSING_PARAMETER, "Public key missing"));
else processRequest(res, data.floID, data.pubKey, data.sign, "Discard Sink", {
type: "discard_sink",
id: data.id,
timestamp: data.timestamp
}, () => sink.discard(id));
}
function ConvertTo(req, res) {
let data = req.body;
processRequest(res, data.floID, data.pubKey, data.sign, "Conversion", {
@ -518,7 +560,7 @@ function GetSink(req, res) {
if (!service)
res.status(INVALID.e_code).send(INVALID.str(eCode.MISSING_PARAMETER, "Missing service parameter"));
else if (!(service in serviceList))
res.status(INVALID.e_code).send(INVALID.str(eCode.INVALID_TYPE, "Invalid service parameter"));
res.status(INVALID.e_code).send(INVALID.str(eCode.INVALID_VALUE, "Invalid service parameter"));
else {
let group;
switch (service) {
@ -640,6 +682,9 @@ module.exports = {
RemoveUserTag,
AddDistributor,
RemoveDistributor,
GenerateSink,
ReshareSink,
DiscardSink,
GetConvertValues,
ConvertTo,
ConvertFrom,