UNPKG

chainpoint-cli

Version:
187 lines (168 loc) 5.84 kB
/* Copyright 2017 Tierion * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * http://www.apache.org/licenses/LICENSE-2.0 * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ const storage = require('./storage.js') const BLAKE2s = require('blake2s-js') const uuidTime = require('uuid-time') const OutputBuilder = require('./output-builder.js') const parallel = require('async-await-parallel') const chp = require('chainpoint-js') const retry = require('async-retry') // The maximum number of hashes that can be submitted per request const POST_HASHES_MAX = 250 async function executeAsync(yargs, argv) { let output = new OutputBuilder('submit') // honor the quiet directive if set let quiet = argv.quiet || false // honor the json directive if set let json = argv.json || false // determine API base URI to use let baseURI = argv.gatewayUri === 'http://0.0.0.0' ? null : argv.gatewayUri let argCount = argv._.length let hashes = [] if (argCount < 2) { // there is no hash parameter output.addErrorResult({ message: `missing hash argument` }) output.display(quiet, json) } else if (argCount === 2) { // this is one hash, or a CSV of hashes hashes = argv._[1].split(',') } else { // this is a list of multiple hashes hashes = argv._.splice(1) } // if there are no valid hashes submitted, abort if (hashes.length === 0) return // parameters are valid, open storage and process submit let hashDb try { hashDb = await storage.connectAsync() } catch (error) { for (let x = 0; x < hashes.length; x++) { output.addErrorResult({ hash: hashes[x], message: `${error.message}` }) } output.display(quiet, json) return } // create submit tasks let allResults = [] let submitTasks = [] let hashSegments = [] // The /hashes endpoint will only accept POST_HASHES_MAX hashes per request // if hashes contains more than POST_HASHES_MAX hashes, break the set up into multiple requests let workingHashSet = hashes.slice() while (workingHashSet.length > 0) hashSegments.push(workingHashSet.splice(0, POST_HASHES_MAX)) for (let x = 0; x < hashSegments.length; x++) { submitTasks.push(() => submitHashesAsync(hashDb, hashSegments[x], baseURI)) } if (submitTasks.length > 0) { try { let submitResults = await parallel(submitTasks, 20) for (let x = 0; x < submitResults.length; x++) { allResults = allResults.concat(submitResults[x]) } } catch (error) { console.error(`ERROR : Could not submit hash(es) : ${error}`) } } for (let x = 0; x < allResults.length; x++) { if (allResults[x].success) { output.addSuccessResult({ proof_id: allResults[x].proof_id, hash: allResults[x].hash, message: allResults[x].message }) } else { output.addErrorResult({ hash: allResults[x].hash, message: allResults[x].message }) } } output.display(quiet, json) } async function submitHashesAsync(hashDb, hashArray, baseURI) { let submitResults = [] let submitResponse try { await retry( async () => { let targetURI = baseURI ? [baseURI] : [] submitResponse = await chp.submitHashes(hashArray, targetURI) }, { retries: 5, // The maximum amount of times to retry the operation. Default is 10 factor: 1, // The exponential factor to use. Default is 2 minTimeout: 10, // The number of milliseconds before starting the first retry. Default is 1000 maxTimeout: 10 } ) /* eslint-enable no-unused-vars */ } catch (error) { for (let x = 0; x < hashArray.length; x++) { submitResults.push({ success: false, hash: hashArray[x], message: 'Unable to submit at this time, try again' }) } return submitResults } for (let x = 0; x < submitResponse.length; x++) { let hashItem = submitResponse[x] let blakeValid = false try { // validate BLAKE2s let hashTimestampMS = parseInt(uuidTime.v1(hashItem.proofId)) let h = new BLAKE2s(5, { personalization: Buffer.from('CHAINPNT') }) let hashStr = [ hashTimestampMS.toString(), hashTimestampMS.toString().length, hashItem.hash, hashItem.hash.length ].join(':') h.update(Buffer.from(hashStr)) let expectedData = Buffer.concat([Buffer.from([0x01]), h.digest()]).toString('hex') let embeddedData = hashItem.proofId.slice(24) if (embeddedData === expectedData) { // the BLAKE2 hash has been validated blakeValid = true await hashDb.insertAsync({ _id: hashItem.proofId, hash: hashItem.hash, gatewayUri: hashItem.uri }) } let submitResult = {} submitResult.success = blakeValid submitResult.proof_id = hashItem.proofId submitResult.hash = hashItem.hash submitResult.message = blakeValid ? 'submitted' : 'refused, bad blake2 value in uuid from node' submitResults.push(submitResult) } catch (error) { let submitResult = {} submitResult.success = false submitResult.proof_id = hashItem.proofId submitResult.hash = hashItem.hash submitResult.message = error.message submitResults.push(submitResult) } } return submitResults } module.exports = { executeAsync: executeAsync }