1
0
mirror of https://github.com/bigchaindb/js-bigchaindb-driver.git synced 2024-11-22 09:46:58 +01:00

Merge pull request #21 from bigchaindb/fix/linting

Lint all the things
This commit is contained in:
Matthias Kretschmann 2017-06-13 15:20:26 +02:00 committed by GitHub
commit 0b0ea0a97e
26 changed files with 295 additions and 289 deletions

View File

@ -4,7 +4,7 @@ node_js: node
install: npm install install: npm install
script: script:
- npm run clean - npm test
- npm run build - npm run build
cache: cache:

View File

@ -18,11 +18,12 @@
"build:cjs": "cross-env BABEL_ENV=cjs babel ./src -d dist/node", "build:cjs": "cross-env BABEL_ENV=cjs babel ./src -d dist/node",
"build:dist": "cross-env NODE_ENV=production webpack -p", "build:dist": "cross-env NODE_ENV=production webpack -p",
"clean": "rimraf dist/bundle dist/node", "clean": "rimraf dist/bundle dist/node",
"test": "echo \"Error: no test specified AWWWW YEAHHH\" && exit 1", "test": "npm run lint",
"release": "./node_modules/release-it/bin/release.js --src.tagName='v%s' --github.release --npm.publish --non-interactive", "release": "./node_modules/release-it/bin/release.js --src.tagName='v%s' --github.release --npm.publish --non-interactive",
"release-minor": "./node_modules/release-it/bin/release.js minor --src.tagName='v%s' --github.release --npm.publish --non-interactive", "release-minor": "./node_modules/release-it/bin/release.js minor --src.tagName='v%s' --github.release --npm.publish --non-interactive",
"release-major": "./node_modules/release-it/bin/release.js major --src.tagName='v%s' --github.release --npm.publish --non-interactive", "release-major": "./node_modules/release-it/bin/release.js major --src.tagName='v%s' --github.release --npm.publish --non-interactive",
"postinstall": "npm run build" "postinstall": "npm run build",
"precommit": "npm run lint"
}, },
"devDependencies": { "devDependencies": {
"babel-cli": "^6.22.2", "babel-cli": "^6.22.2",
@ -41,6 +42,7 @@
"eslint": "^3.14.1", "eslint": "^3.14.1",
"eslint-config-ascribe": "^3.0.1", "eslint-config-ascribe": "^3.0.1",
"eslint-plugin-import": "^2.2.0", "eslint-plugin-import": "^2.2.0",
"husky": "^0.13.4",
"release-it": "^2.7.3", "release-it": "^2.7.3",
"rimraf": "^2.5.4", "rimraf": "^2.5.4",
"webpack": "^2.2.1" "webpack": "^2.2.1"
@ -58,6 +60,7 @@
"js-sha3": "^0.5.7", "js-sha3": "^0.5.7",
"js-utility-belt": "^1.5.0", "js-utility-belt": "^1.5.0",
"json-stable-stringify": "^1.0.1", "json-stable-stringify": "^1.0.1",
"query-string": "^4.3.4",
"sprintf-js": "^1.0.3", "sprintf-js": "^1.0.3",
"tweetnacl": "^1.0.0" "tweetnacl": "^1.0.0"
}, },

View File

@ -1,6 +1,5 @@
import base58 from 'bs58'; import base58 from 'bs58'
import nacl from 'tweetnacl'; import nacl from 'tweetnacl'
import sha3 from 'js-sha3';
/** /**
* @public * @public
@ -11,8 +10,8 @@ import sha3 from 'js-sha3';
* @property {string} privateKey * @property {string} privateKey
*/ */
export default function Ed25519Keypair(seed) { export default function Ed25519Keypair(seed) {
const keyPair = seed ? nacl.sign.keyPair.fromSeed(seed) : nacl.sign.keyPair(); const keyPair = seed ? nacl.sign.keyPair.fromSeed(seed) : nacl.sign.keyPair()
this.publicKey = base58.encode(keyPair.publicKey); this.publicKey = base58.encode(keyPair.publicKey)
// tweetnacl's generated secret key is the secret key + public key (resulting in a 64-byte buffer) // tweetnacl's generated secret key is the secret key + public key (resulting in a 64-byte buffer)
this.privateKey = base58.encode(keyPair.secretKey.slice(0, 32)); this.privateKey = base58.encode(keyPair.secretKey.slice(0, 32))
} }

View File

@ -1,13 +1,13 @@
import { Promise } from 'es6-promise'; import { Promise } from 'es6-promise'
import fetchPonyfill from 'fetch-ponyfill'; import fetchPonyfill from 'fetch-ponyfill'
import { vsprintf } from 'sprintf-js'; import { vsprintf } from 'sprintf-js'
import formatText from './format_text'; import formatText from './format_text'
import stringifyAsQueryParam from './stringify_as_query_param'; import stringifyAsQueryParam from './stringify_as_query_param'
const fetch = fetchPonyfill(Promise); const fetch = fetchPonyfill(Promise)
/** /**
@ -38,35 +38,35 @@ const fetch = fetchPonyfill(Promise);
* otherwise rejects with the response * otherwise rejects with the response
*/ */
export default function baseRequest(url, { jsonBody, query, urlTemplateSpec, ...fetchConfig } = {}) { export default function baseRequest(url, { jsonBody, query, urlTemplateSpec, ...fetchConfig } = {}) {
let expandedUrl = url; let expandedUrl = url
if (urlTemplateSpec != null) { if (urlTemplateSpec != null) {
if (Array.isArray(urlTemplateSpec) && urlTemplateSpec.length) { if (Array.isArray(urlTemplateSpec) && urlTemplateSpec.length) {
// Use vsprintf for the array call signature // Use vsprintf for the array call signature
expandedUrl = vsprintf(url, urlTemplateSpec); expandedUrl = vsprintf(url, urlTemplateSpec)
} else if (urlTemplateSpec && } else if (urlTemplateSpec &&
typeof urlTemplateSpec === 'object' && typeof urlTemplateSpec === 'object' &&
Object.keys(urlTemplateSpec).length) { Object.keys(urlTemplateSpec).length) {
expandedUrl = formatText(url, urlTemplateSpec); expandedUrl = formatText(url, urlTemplateSpec)
} else if (process.env.NODE_ENV !== 'production') { } else if (process.env.NODE_ENV !== 'production') {
// eslint-disable-next-line no-console // eslint-disable-next-line no-console
console.warn('Supplied urlTemplateSpec was not an array or object. Ignoring...'); console.warn('Supplied urlTemplateSpec was not an array or object. Ignoring...')
} }
} }
if (query != null) { if (query != null) {
if (typeof query === 'string') { if (typeof query === 'string') {
expandedUrl += query; expandedUrl += query
} else if (query && typeof query === 'object') { } else if (query && typeof query === 'object') {
expandedUrl += stringifyAsQueryParam(query); expandedUrl += stringifyAsQueryParam(query)
} else if (process.env.NODE_ENV !== 'production') { } else if (process.env.NODE_ENV !== 'production') {
// eslint-disable-next-line no-console // eslint-disable-next-line no-console
console.warn('Supplied query was not a string or object. Ignoring...'); console.warn('Supplied query was not a string or object. Ignoring...')
} }
} }
if (jsonBody != null) { if (jsonBody != null) {
fetchConfig.body = JSON.stringify(jsonBody); fetchConfig.body = JSON.stringify(jsonBody)
} }
return fetch.fetch(expandedUrl, fetchConfig) return fetch.fetch(expandedUrl, fetchConfig)
@ -74,8 +74,8 @@ export default function baseRequest(url, { jsonBody, query, urlTemplateSpec, ...
// If status is not a 2xx (based on Response.ok), assume it's an error // If status is not a 2xx (based on Response.ok), assume it's an error
// See https://developer.mozilla.org/en-US/docs/Web/API/GlobalFetch/fetch // See https://developer.mozilla.org/en-US/docs/Web/API/GlobalFetch/fetch
if (!(res && res.ok)) { if (!(res && res.ok)) {
throw res; throw res
} }
return res; return res
}); })
} }

View File

@ -1,27 +1,27 @@
import request from '../request'; import request from '../request'
export default class Connection { export default class Connection {
constructor(path, headers) { constructor(path, headers) {
this.path = path; this.path = path
this.headers = headers; this.headers = headers
} }
getApiUrls(endpoints) { getApiUrls(endpoints) {
// TODO: Use camel case // TODO: Use camel case
return { return {
'blocks': this.path + 'blocks', 'blocks': `${this.path}blocks`,
'blocks_detail': this.path + 'blocks/%(blockId)s', 'blocks_detail': `${this.path}blocks/%(blockId)s`,
'outputs': this.path + 'outputs', 'outputs': `${this.path}outputs`,
'statuses': this.path + 'statuses', 'statuses': `${this.path}statuses`,
'transactions': this.path + 'transactions', 'transactions': `${this.path}transactions`,
'transactions_detail': this.path + 'transactions/%(txId)s', 'transactions_detail': `${this.path}transactions/%(txId)s`,
'search_assets': this.path + 'assets', 'search_assets': `${this.path}assets`,
'votes': this.path + 'votes' 'votes': `${this.path}votes`
}[endpoints]; }[endpoints]
} }
_req(path, options={}) { _req(path, options = {}) {
// NOTE: `options.headers` could be undefined, but that's OK. // NOTE: `options.headers` could be undefined, but that's OK.
options.headers = Object.assign({}, options.headers, this.headers) options.headers = Object.assign({}, options.headers, this.headers)
return request(path, options) return request(path, options)
@ -33,22 +33,22 @@ export default class Connection {
*/ */
getBlock(blockId) { getBlock(blockId) {
return this._req(this.getApiUrls('blocks_detail'), { return this._req(this.getApiUrls('blocks_detail'), {
urlTemplateSpec: { urlTemplateSpec: {
blockId blockId
} }
}); })
} }
/** /**
* @public * @public
* @param tx_id * @param tx_id
*/ */
getStatus(tx_id) { getStatus(tx_id) { // eslint-disable-line camelcase
return this._req(this.getApiUrls('statuses'), { return this._req(this.getApiUrls('statuses'), {
query: { query: {
tx_id tx_id
} }
}); })
} }
/** /**
@ -57,10 +57,10 @@ export default class Connection {
*/ */
getTransaction(txId) { getTransaction(txId) {
return this._req(this.getApiUrls('transactions_detail'), { return this._req(this.getApiUrls('transactions_detail'), {
urlTemplateSpec: { urlTemplateSpec: {
txId txId
} }
}); })
} }
/** /**
@ -70,11 +70,11 @@ export default class Connection {
*/ */
listBlocks({ tx_id, status }) { listBlocks({ tx_id, status }) {
return this._req(this.getApiUrls('blocks'), { return this._req(this.getApiUrls('blocks'), {
query: { query: {
tx_id, tx_id,
status status
} }
}); })
} }
/** /**
@ -83,7 +83,7 @@ export default class Connection {
* @param unspent * @param unspent
* @param onlyJsonResponse * @param onlyJsonResponse
*/ */
listOutputs({ public_key, unspent }, onlyJsonResponse=true) { listOutputs({ public_key, unspent }, onlyJsonResponse = true) {
return this._req(this.getApiUrls('outputs'), { return this._req(this.getApiUrls('outputs'), {
query: { query: {
public_key, public_key,
@ -110,38 +110,38 @@ export default class Connection {
* @public * @public
* @param block_id * @param block_id
*/ */
listVotes(block_id) { listVotes(block_id) { // eslint-disable-line camelcase
return this._req(this.getApiUrls('votes'), { return this._req(this.getApiUrls('votes'), {
query: { query: {
block_id block_id
} }
}); })
} }
/** /**
* @public * @public
* @param tx_id * @param txId
* @return {Promise} * @return {Promise}
*/ */
pollStatusAndFetchTransaction(tx_id) { pollStatusAndFetchTransaction(txId) {
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
const timer = setInterval(() => { const timer = setInterval(() => {
this.getStatus(tx_id) this.getStatus(txId)
.then((res) => { .then((res) => {
console.log('Fetched transaction status:', res); console.log('Fetched transaction status:', res) // eslint-disable-line no-console
if (res.status === 'valid') { if (res.status === 'valid') {
clearInterval(timer); clearInterval(timer)
this.getTransaction(tx_id) this.getTransaction(txId)
.then((res) => { .then((res_) => {
console.log('Fetched transaction:', res); console.log('Fetched transaction:', res_) // eslint-disable-line no-console
resolve(res); resolve(res_)
}); })
} }
}) })
.catch((err) => { .catch((err) => {
clearInterval(timer); clearInterval(timer)
reject(err); reject(err)
}); })
}, 500) }, 500)
}) })
} }

View File

@ -1,13 +1,13 @@
import { sprintf } from 'sprintf-js'; import { sprintf } from 'sprintf-js'
// Regexes taken from or inspired by sprintf-js // Regexes taken from or inspired by sprintf-js
const Regex = { const Regex = {
TEMPLATE_LITERAL: /\${([^\)]+?)}/g, TEMPLATE_LITERAL: /\${([^)]+?)}/g,
KEY: /^([a-z_][a-z_\d]*)/i, KEY: /^([a-z_][a-z_\d]*)/i,
KEY_ACCESS: /^\.([a-z_][a-z_\d]*)/i, KEY_ACCESS: /^\.([a-z_][a-z_\d]*)/i,
INDEX_ACCESS: /^\[(\d+)\]/ INDEX_ACCESS: /^\[(\d+)\]/
}; }
/** /**
* imported from https://github.com/bigchaindb/js-utility-belt/ * imported from https://github.com/bigchaindb/js-utility-belt/
@ -37,14 +37,14 @@ const Regex = {
* => 'Berlin is best known for its Currywurst' * => 'Berlin is best known for its Currywurst'
*/ */
export default function formatText(s, ...argv) { export default function formatText(s, ...argv) {
let expandedFormatStr = s; let expandedFormatStr = s
// Try to replace formats of the form '${...}' if named replacement fields are used // Try to replace formats of the form '${...}' if named replacement fields are used
if (s && argv.length === 1 && typeof argv[0] === 'object') { if (s && argv.length === 1 && typeof argv[0] === 'object') {
const templateSpecObj = argv[0]; const templateSpecObj = argv[0]
expandedFormatStr = s.replace(Regex.TEMPLATE_LITERAL, (match, replacement) => { expandedFormatStr = s.replace(Regex.TEMPLATE_LITERAL, (match, replacement) => {
let interpolationLeft = replacement; let interpolationLeft = replacement
/** /**
* Interpolation algorithm inspired by sprintf-js. * Interpolation algorithm inspired by sprintf-js.
@ -61,21 +61,21 @@ export default function formatText(s, ...argv) {
* And that in the regexes defined, the first matching group always corresponds to the * And that in the regexes defined, the first matching group always corresponds to the
* property matched. * property matched.
*/ */
let value; let value
let curMatch = Regex.KEY.exec(interpolationLeft); let curMatch = Regex.KEY.exec(interpolationLeft)
if (curMatch !== null) { if (curMatch !== null) {
value = templateSpecObj[curMatch[1]]; value = templateSpecObj[curMatch[1]]
// Assigning in the conditionals here makes the code less bloated // Assigning in the conditionals here makes the code less bloated
/* eslint-disable no-cond-assign */ /* eslint-disable no-cond-assign */
while ((interpolationLeft = interpolationLeft.substring(curMatch[0].length)) && while ((interpolationLeft = interpolationLeft.substring(curMatch[0].length)) &&
value != null) { value != null) {
if ((curMatch = Regex.KEY_ACCESS.exec(interpolationLeft))) { if ((curMatch = Regex.KEY_ACCESS.exec(interpolationLeft))) {
value = value[curMatch[1]]; value = value[curMatch[1]]
} else if ((curMatch = Regex.INDEX_ACCESS.exec(interpolationLeft))) { } else if ((curMatch = Regex.INDEX_ACCESS.exec(interpolationLeft))) {
value = value[curMatch[1]]; value = value[curMatch[1]]
} else { } else {
break; break
} }
} }
/* eslint-enable no-cond-assign */ /* eslint-enable no-cond-assign */
@ -86,12 +86,12 @@ export default function formatText(s, ...argv) {
if (interpolationLeft.length) { if (interpolationLeft.length) {
throw new SyntaxError( throw new SyntaxError(
`[formatText] failed to parse named argument key: ${replacement}` `[formatText] failed to parse named argument key: ${replacement}`
); )
} }
return value; return value
}); })
} }
return sprintf(expandedFormatStr, ...argv); return sprintf(expandedFormatStr, ...argv)
} }

View File

@ -1,5 +1,5 @@
export Ed25519Keypair from './Ed25519Keypair'; export Ed25519Keypair from './Ed25519Keypair'
export * as Transaction from './transaction'; export * as Transaction from './transaction'
export Connection from './connection'; export Connection from './connection'

View File

@ -1,43 +1,41 @@
import baseRequest from './baseRequest'; import baseRequest from './baseRequest'
import sanitize from './sanitize'; import sanitize from './sanitize'
const DEFAULT_REQUEST_CONFIG = { const DEFAULT_REQUEST_CONFIG = {
headers: { headers: {
'Accept': 'application/json' 'Accept': 'application/json'
} }
}; }
/** /**
* Small wrapper around js-utility-belt's request that provides url resolving, * Small wrapper around js-utility-belt's request that provides url resolving,
* default settings, and response handling. * default settings, and response handling.
*/ */
export default function request(url, config = {}, onlyJsonResponse=true) { export default function request(url, config = {}, onlyJsonResponse = true) {
// Load default fetch configuration and remove any falsy query parameters // Load default fetch configuration and remove any falsy query parameters
const requestConfig = Object.assign({}, DEFAULT_REQUEST_CONFIG, config, { const requestConfig = Object.assign({}, DEFAULT_REQUEST_CONFIG, config, {
query: config.query && sanitize(config.query) query: config.query && sanitize(config.query)
}); })
let apiUrl = url; const apiUrl = url
if (requestConfig.jsonBody) { if (requestConfig.jsonBody) {
requestConfig.headers = Object.assign({}, requestConfig.headers, { requestConfig.headers = Object.assign({}, requestConfig.headers, {
'Content-Type': 'application/json' 'Content-Type': 'application/json'
}); })
} }
if (!url) { if (!url) {
return Promise.reject(new Error('Request was not given a url.')); return Promise.reject(new Error('Request was not given a url.'))
} }
return baseRequest(apiUrl, requestConfig) return baseRequest(apiUrl, requestConfig)
.then((res) => { .then((res) => onlyJsonResponse ? res.json() : // eslint-disable-line no-confusing-arrow
return onlyJsonResponse ? res.json() : {
{ json: res.json(),
json: res.json(), url: res.url
url: res.url
};
}) })
.catch((err) => { .catch((err) => {
console.error(err); console.error(err)
throw err; throw err
}); })
} }

View File

@ -1,5 +1,5 @@
import coreIncludes from 'core-js/library/fn/array/includes'; import coreIncludes from 'core-js/library/fn/array/includes'
import coreObjectEntries from 'core-js/library/fn/object/entries'; import coreObjectEntries from 'core-js/library/fn/object/entries'
/** /**
@ -10,13 +10,13 @@ import coreObjectEntries from 'core-js/library/fn/object/entries';
function filterFromObject(obj, filter, { isInclusion = true } = {}) { function filterFromObject(obj, filter, { isInclusion = true } = {}) {
if (filter && Array.isArray(filter)) { if (filter && Array.isArray(filter)) {
return applyFilterOnObject(obj, isInclusion ? ((_, key) => coreIncludes(filter, key)) return applyFilterOnObject(obj, isInclusion ? ((_, key) => coreIncludes(filter, key))
: ((_, key) => !coreIncludes(filter, key))); : ((_, key) => !coreIncludes(filter, key)))
} else if (filter && typeof filter === 'function') { } else if (filter && typeof filter === 'function') {
// Flip the filter fn's return if it's for inclusion // Flip the filter fn's return if it's for inclusion
return applyFilterOnObject(obj, isInclusion ? filter return applyFilterOnObject(obj, isInclusion ? filter
: (...args) => !filter(...args)); : (...args) => !filter(...args))
} else { } else {
throw new Error('The given filter is not an array or function. Exclude aborted'); throw new Error('The given filter is not an array or function. Exclude aborted')
} }
} }
@ -26,17 +26,17 @@ function filterFromObject(obj, filter, { isInclusion = true } = {}) {
*/ */
function applyFilterOnObject(obj, filterFn) { function applyFilterOnObject(obj, filterFn) {
if (filterFn == null) { if (filterFn == null) {
return Object.assign({}, obj); return Object.assign({}, obj)
} }
const filteredObj = {}; const filteredObj = {}
coreObjectEntries(obj).forEach(([key, val]) => { coreObjectEntries(obj).forEach(([key, val]) => {
if (filterFn(val, key)) { if (filterFn(val, key)) {
filteredObj[key] = val; filteredObj[key] = val
} }
}); })
return filteredObj; return filteredObj
} }
/** /**
@ -48,7 +48,7 @@ function applyFilterOnObject(obj, filterFn) {
* @return {object} The new object * @return {object} The new object
*/ */
function selectFromObject(obj, filter) { function selectFromObject(obj, filter) {
return filterFromObject(obj, filter); return filterFromObject(obj, filter)
} }
/** /**
@ -60,5 +60,5 @@ function selectFromObject(obj, filter) {
* @return {object} Sanitized Javascript object * @return {object} Sanitized Javascript object
*/ */
export default function sanitize(obj) { export default function sanitize(obj) {
return selectFromObject(obj, (val) => !!val); return selectFromObject(obj, (val) => !!val)
} }

View File

@ -1,8 +1,8 @@
import sha3 from 'js-sha3'; import sha3 from 'js-sha3'
export default function sha256Hash(data) { export default function sha256Hash(data) {
return sha3.sha3_256 return sha3.sha3_256
.create() .create()
.update(data) .update(data)
.hex(); .hex()
} }

View File

@ -1,6 +1,6 @@
import coreObjectEntries from 'core-js/library/fn/object/entries'; import coreObjectEntries from 'core-js/library/fn/object/entries'
import decamelize from 'decamelize'; import decamelize from 'decamelize'
import queryString from 'query-string'; import queryString from 'query-string'
/** /**
@ -30,13 +30,13 @@ import queryString from 'query-string';
*/ */
export default function stringifyAsQueryParam(obj, transform = decamelize) { export default function stringifyAsQueryParam(obj, transform = decamelize) {
if (!obj || typeof obj !== 'object' || !Object.keys(obj).length) { if (!obj || typeof obj !== 'object' || !Object.keys(obj).length) {
return ''; return ''
} }
const transformedKeysObj = coreObjectEntries(obj).reduce((paramsObj, [key, value]) => { const transformedKeysObj = coreObjectEntries(obj).reduce((paramsObj, [key, value]) => {
paramsObj[transform(key)] = value; paramsObj[transform(key)] = value
return paramsObj; return paramsObj
}, {}); }, {})
return `?${queryString.stringify(transformedKeysObj)}`; return `?${queryString.stringify(transformedKeysObj)}`
} }

View File

@ -1,10 +1,10 @@
import serializeTransactionIntoCanonicalString from './serializeTransactionIntoCanonicalString'; import serializeTransactionIntoCanonicalString from './serializeTransactionIntoCanonicalString'
import sha256Hash from '../sha256Hash'; import sha256Hash from '../sha256Hash'
export default function hashTransaction(transaction) { export default function hashTransaction(transaction) {
// Safely remove any tx id from the given transaction for hashing // Safely remove any tx id from the given transaction for hashing
const tx = { ...transaction }; const tx = { ...transaction }
delete tx.id; delete tx.id
return sha256Hash(serializeTransactionIntoCanonicalString(tx)); return sha256Hash(serializeTransactionIntoCanonicalString(tx))
} }

View File

@ -1,11 +1,11 @@
export makeEd25519Condition from './makeEd25519Condition'; export makeEd25519Condition from './makeEd25519Condition'
export makeSha256Condition from './makeSha256Condition'; export makeSha256Condition from './makeSha256Condition'
export makeThresholdCondition from './makeThresholdCondition'; export makeThresholdCondition from './makeThresholdCondition'
export makeCreateTransaction from './makeCreateTransaction'; export makeCreateTransaction from './makeCreateTransaction'
export makeOutput from './makeOutput'; export makeOutput from './makeOutput'
export makeTransaction from './makeTransaction'; export makeTransaction from './makeTransaction'
export makeTransferTransaction from './makeTransferTransaction'; export makeTransferTransaction from './makeTransferTransaction'
export serializeTransactionIntoCanonicalString from './serializeTransactionIntoCanonicalString'; export serializeTransactionIntoCanonicalString from './serializeTransactionIntoCanonicalString'
export signTransaction from './signTransaction'; export signTransaction from './signTransaction'
export ccJsonLoad from './utils/ccJsonLoad'; export ccJsonLoad from './utils/ccJsonLoad'
export ccJsonify from './utils/ccJsonify'; export ccJsonify from './utils/ccJsonify'

View File

@ -1,5 +1,5 @@
import makeInputTemplate from './makeInputTemplate'; import makeInputTemplate from './makeInputTemplate'
import makeTransaction from './makeTransaction'; import makeTransaction from './makeTransaction'
/** /**
@ -24,8 +24,8 @@ import makeTransaction from './makeTransaction';
export default function makeCreateTransaction(asset, metadata, outputs, ...issuers) { export default function makeCreateTransaction(asset, metadata, outputs, ...issuers) {
const assetDefinition = { const assetDefinition = {
'data': asset || null, 'data': asset || null,
}; }
const inputs = issuers.map((issuer) => makeInputTemplate([issuer])); const inputs = issuers.map((issuer) => makeInputTemplate([issuer]))
return makeTransaction('CREATE', assetDefinition, metadata, outputs, inputs); return makeTransaction('CREATE', assetDefinition, metadata, outputs, inputs)
} }

View File

@ -1,9 +1,9 @@
import { Buffer } from 'buffer'; import { Buffer } from 'buffer'
import base58 from 'bs58'; import base58 from 'bs58'
import cc from 'five-bells-condition'; import cc from 'five-bells-condition'
import ccJsonify from './utils/ccJsonify'; import ccJsonify from './utils/ccJsonify'
/** /**
@ -13,15 +13,15 @@ import ccJsonify from './utils/ccJsonify';
* @param {boolean} [json=true] If true returns a json object otherwise a crypto-condition type * @param {boolean} [json=true] If true returns a json object otherwise a crypto-condition type
* @returns {object} Ed25519 Condition (that will need to wrapped in an Output) * @returns {object} Ed25519 Condition (that will need to wrapped in an Output)
*/ */
export default function makeEd25519Condition(publicKey, json=true) { export default function makeEd25519Condition(publicKey, json = true) {
const publicKeyBuffer = new Buffer(base58.decode(publicKey)); const publicKeyBuffer = new Buffer(base58.decode(publicKey))
const ed25519Fulfillment = new cc.Ed25519(); const ed25519Fulfillment = new cc.Ed25519()
ed25519Fulfillment.setPublicKey(publicKeyBuffer); ed25519Fulfillment.setPublicKey(publicKeyBuffer)
if (json) { if (json) {
return ccJsonify(ed25519Fulfillment) return ccJsonify(ed25519Fulfillment)
} }
return ed25519Fulfillment; return ed25519Fulfillment
} }

View File

@ -3,5 +3,5 @@ export default function makeInputTemplate(publicKeys = [], fulfills = null, fulf
fulfillment, fulfillment,
fulfills, fulfills,
'owners_before': publicKeys, 'owners_before': publicKeys,
}; }
} }

View File

@ -8,9 +8,9 @@
*/ */
export default function makeOutput(condition, amount = 1) { export default function makeOutput(condition, amount = 1) {
return { return {
amount: amount.toString(), 'amount': amount.toString(),
condition, condition,
'public_keys': condition.details.hasOwnProperty('public_key') ? 'public_keys': condition.details.hasOwnProperty('public_key') ?
[condition.details.public_key] : [], [condition.details.public_key] : [],
}; }
} }

View File

@ -1,8 +1,8 @@
import { Buffer } from 'buffer'; import { Buffer } from 'buffer'
import cc from 'five-bells-condition'; import cc from 'five-bells-condition'
import ccJsonify from './utils/ccJsonify'; import ccJsonify from './utils/ccJsonify'
/** /**
@ -12,12 +12,12 @@ import ccJsonify from './utils/ccJsonify';
* @param {boolean} [json=true] If true returns a json object otherwise a crypto-condition type * @param {boolean} [json=true] If true returns a json object otherwise a crypto-condition type
* @returns {object} Preimage-Sha256 Condition (that will need to wrapped in an Output) * @returns {object} Preimage-Sha256 Condition (that will need to wrapped in an Output)
*/ */
export default function makeSha256Condition(preimage, json=true) { export default function makeSha256Condition(preimage, json = true) {
const sha256Fulfillment = new cc.PreimageSha256(); const sha256Fulfillment = new cc.PreimageSha256()
sha256Fulfillment.preimage = new Buffer(preimage); sha256Fulfillment.preimage = new Buffer(preimage)
if (json) { if (json) {
return ccJsonify(sha256Fulfillment) return ccJsonify(sha256Fulfillment)
} }
return sha256Fulfillment; return sha256Fulfillment
} }

View File

@ -1,6 +1,6 @@
import cc from 'five-bells-condition'; import cc from 'five-bells-condition'
import ccJsonify from './utils/ccJsonify'; import ccJsonify from './utils/ccJsonify'
/** /**
@ -11,14 +11,14 @@ import ccJsonify from './utils/ccJsonify';
* @param {boolean} [json=true] If true returns a json object otherwise a crypto-condition type * @param {boolean} [json=true] If true returns a json object otherwise a crypto-condition type
* @returns {object} Sha256 Threshold Condition (that will need to wrapped in an Output) * @returns {object} Sha256 Threshold Condition (that will need to wrapped in an Output)
*/ */
export default function makeThresholdCondition(threshold, subconditions=[], json=true) { export default function makeThresholdCondition(threshold, subconditions = [], json = true) {
const thresholdCondition = new cc.ThresholdSha256(); const thresholdCondition = new cc.ThresholdSha256()
thresholdCondition.threshold = threshold; thresholdCondition.threshold = threshold
subconditions.forEach((subcondition) => { subconditions.forEach((subcondition) => {
// TODO: add support for Condition and URIs // TODO: add support for Condition and URIs
thresholdCondition.addSubfulfillment(subcondition); thresholdCondition.addSubfulfillment(subcondition)
}); })
if (json) { if (json) {
return ccJsonify(thresholdCondition) return ccJsonify(thresholdCondition)

View File

@ -1,4 +1,4 @@
import hashTransaction from './hashTransaction'; import hashTransaction from './hashTransaction'
function makeTransactionTemplate() { function makeTransactionTemplate() {
@ -10,19 +10,19 @@ function makeTransactionTemplate() {
'metadata': null, 'metadata': null,
'asset': null, 'asset': null,
'version': '0.9', 'version': '0.9',
}; }
} }
export default function makeTransaction(operation, asset, metadata = null, outputs = [], inputs = []) { export default function makeTransaction(operation, asset, metadata = null, outputs = [], inputs = []) {
const tx = makeTransactionTemplate(); const tx = makeTransactionTemplate()
tx.operation = operation; tx.operation = operation
tx.asset = asset; tx.asset = asset
tx.metadata = metadata; tx.metadata = metadata
tx.inputs = inputs; tx.inputs = inputs
tx.outputs = outputs; tx.outputs = outputs
// Hashing must be done after, as the hash is of the Transaction (up to now) // Hashing must be done after, as the hash is of the Transaction (up to now)
tx.id = hashTransaction(tx); tx.id = hashTransaction(tx)
return tx; return tx
} }

View File

@ -1,5 +1,5 @@
import makeInputTemplate from './makeInputTemplate'; import makeInputTemplate from './makeInputTemplate'
import makeTransaction from './makeTransaction'; import makeTransaction from './makeTransaction'
/** /**
@ -22,21 +22,26 @@ import makeTransaction from './makeTransaction';
* @returns {object} Unsigned transaction -- make sure to call signTransaction() on it before * @returns {object} Unsigned transaction -- make sure to call signTransaction() on it before
* sending it off! * sending it off!
*/ */
export default function makeTransferTransaction(unspentTransaction, metadata, outputs, ...fulfilledOutputs) { export default function makeTransferTransaction(
unspentTransaction,
metadata,
outputs,
...fulfilledOutputs
) {
const inputs = fulfilledOutputs.map((outputIndex) => { const inputs = fulfilledOutputs.map((outputIndex) => {
const fulfilledOutput = unspentTransaction.outputs[outputIndex]; const fulfilledOutput = unspentTransaction.outputs[outputIndex]
const transactionLink = { const transactionLink = {
'output': outputIndex, 'output': outputIndex,
'txid': unspentTransaction.id, 'txid': unspentTransaction.id,
}; }
return makeInputTemplate(fulfilledOutput.public_keys, transactionLink); return makeInputTemplate(fulfilledOutput.public_keys, transactionLink)
}); })
const assetLink = { const assetLink = {
'id': unspentTransaction.operation === 'CREATE' ? unspentTransaction.id 'id': unspentTransaction.operation === 'CREATE' ? unspentTransaction.id
: unspentTransaction.asset.id : unspentTransaction.asset.id
}; }
return makeTransaction('TRANSFER', assetLink, metadata, outputs, inputs); return makeTransaction('TRANSFER', assetLink, metadata, outputs, inputs)
} }

View File

@ -1,5 +1,5 @@
import stableStringify from 'json-stable-stringify'; import stableStringify from 'json-stable-stringify'
import clone from 'clone'; import clone from 'clone'
/** /**
@ -10,8 +10,8 @@ import clone from 'clone';
*/ */
export default function serializeTransactionIntoCanonicalString(transaction) { export default function serializeTransactionIntoCanonicalString(transaction) {
// BigchainDB signs fulfillments by serializing transactions into a "canonical" format where // BigchainDB signs fulfillments by serializing transactions into a "canonical" format where
const tx = clone(transaction); const tx = clone(transaction)
// TODO: set fulfillments to null // TODO: set fulfillments to null
// Sort the keys // Sort the keys
return stableStringify(tx, (a, b) => (a.key > b.key ? 1 : -1)); return stableStringify(tx, (a, b) => (a.key > b.key ? 1 : -1))
} }

View File

@ -1,9 +1,9 @@
import { Buffer } from 'buffer'; import { Buffer } from 'buffer'
import base58 from 'bs58'; import base58 from 'bs58'
import cc from 'five-bells-condition'; import cc from 'five-bells-condition'
import clone from 'clone'; import clone from 'clone'
import serializeTransactionIntoCanonicalString from './serializeTransactionIntoCanonicalString'; import serializeTransactionIntoCanonicalString from './serializeTransactionIntoCanonicalString'
/** /**
@ -19,17 +19,17 @@ import serializeTransactionIntoCanonicalString from './serializeTransactionIntoC
* @returns {object} The signed version of `transaction`. * @returns {object} The signed version of `transaction`.
*/ */
export default function signTransaction(transaction, ...privateKeys) { export default function signTransaction(transaction, ...privateKeys) {
const signedTx = clone(transaction); const signedTx = clone(transaction)
signedTx.inputs.forEach((input, index) => { signedTx.inputs.forEach((input, index) => {
const privateKey = privateKeys[index]; const privateKey = privateKeys[index]
const privateKeyBuffer = new Buffer(base58.decode(privateKey)); const privateKeyBuffer = new Buffer(base58.decode(privateKey))
const serializedTransaction = serializeTransactionIntoCanonicalString(transaction); const serializedTransaction = serializeTransactionIntoCanonicalString(transaction)
const ed25519Fulfillment = new cc.Ed25519(); const ed25519Fulfillment = new cc.Ed25519()
ed25519Fulfillment.sign(new Buffer(serializedTransaction), privateKeyBuffer); ed25519Fulfillment.sign(new Buffer(serializedTransaction), privateKeyBuffer)
const fulfillmentUri = ed25519Fulfillment.serializeUri(); const fulfillmentUri = ed25519Fulfillment.serializeUri()
input.fulfillment = fulfillmentUri; input.fulfillment = fulfillmentUri
}); })
return signedTx; return signedTx
} }

View File

@ -1,6 +1,6 @@
import base58 from 'bs58'; import { Buffer } from 'buffer'
import cc from 'five-bells-condition'; import base58 from 'bs58'
import { Buffer } from 'buffer'; import cc from 'five-bells-condition'
/** /**
* @public * @public
@ -9,41 +9,41 @@ import { Buffer } from 'buffer';
* @returns {cc.Condition} Ed25519 Condition (that will need to wrapped in an Output) * @returns {cc.Condition} Ed25519 Condition (that will need to wrapped in an Output)
*/ */
export default function ccJsonLoad(conditionJson) { export default function ccJsonLoad(conditionJson) {
if ('hash' in conditionJson) { if ('hash' in conditionJson) {
let condition = new cc.Condition(); const condition = new cc.Condition()
condition.type = conditionJson.type_id; condition.type = conditionJson.type_id
condition.bitmask = conditionJson.bitmask; condition.bitmask = conditionJson.bitmask
condition.hash = new Buffer(base58.decode(conditionJson.hash)); condition.hash = new Buffer(base58.decode(conditionJson.hash))
condition.maxFulfillmentLength = parseInt(conditionJson.max_fulfillment_length, 10); condition.maxFulfillmentLength = parseInt(conditionJson.max_fulfillment_length, 10)
return condition return condition
} else { } else {
let fulfillment; let fulfillment
if (conditionJson.type_id === 2) { if (conditionJson.type_id === 2) {
fulfillment = new cc.ThresholdSha256(); fulfillment = new cc.ThresholdSha256()
fulfillment.threshold = conditionJson.threshold; fulfillment.threshold = conditionJson.threshold
conditionJson.subfulfillments.forEach((subfulfillment) => { conditionJson.subfulfillments.forEach((subfulfillmentJson) => {
subfulfillment = ccJsonLoad(subfulfillment); const subfulfillment = ccJsonLoad(subfulfillmentJson)
if ('getConditionUri' in subfulfillment) if ('getConditionUri' in subfulfillment) {
fulfillment.addSubfulfillment(subfulfillment); fulfillment.addSubfulfillment(subfulfillment)
else if ('serializeUri' in subfulfillment) } else if ('serializeUri' in subfulfillment) {
fulfillment.addSubcondition(subfulfillment) fulfillment.addSubcondition(subfulfillment)
}
}) })
} }
if (conditionJson.type_id === 0) { if (conditionJson.type_id === 0) {
fulfillment = new cc.PreimageSha256(); fulfillment = new cc.PreimageSha256()
fulfillment.preimage = new Buffer(conditionJson.preimage); fulfillment.preimage = new Buffer(conditionJson.preimage)
} }
if (conditionJson.type_id === 4) { if (conditionJson.type_id === 4) {
fulfillment = new cc.Ed25519(); fulfillment = new cc.Ed25519()
fulfillment.publicKey = new Buffer(base58.decode(conditionJson.public_key)); fulfillment.publicKey = new Buffer(base58.decode(conditionJson.public_key))
if (conditionJson.signature) if (conditionJson.signature) {
fulfillment.signature = new Buffer(base58.decode(conditionJson.signature)); fulfillment.signature = new Buffer(base58.decode(conditionJson.signature))
}
} }
return fulfillment; return fulfillment
} }
} }

View File

@ -1,36 +1,36 @@
import base58 from 'bs58'; import base58 from 'bs58'
/** /**
* @public * @public
* Serializes a crypto-condition class (Condition or Fulfillment) into a BigchainDB-compatible JSON * Serializes a crypto-condition class (Condition or Fulfillment) into a BigchainDB-compatible JSON
* @param {cc.Fulfillment} fulfillment base58 encoded Ed25519 public key for the recipient of the Transaction * @param {cc.Fulfillment} fulfillment base58 encoded Ed25519 public key for recipient of the Transaction
* @returns {object} Ed25519 Condition (that will need to wrapped in an Output) * @returns {object} Ed25519 Condition (that will need to wrapped in an Output)
*/ */
export default function ccJsonify(fulfillment) { export default function ccJsonify(fulfillment) {
let conditionUri
let conditionUri; if ('getConditionUri' in fulfillment) {
conditionUri = fulfillment.getConditionUri()
} else if ('serializeUri' in fulfillment) {
conditionUri = fulfillment.serializeUri()
}
if ('getConditionUri' in fulfillment) const jsonBody = {
conditionUri = fulfillment.getConditionUri();
else if ('serializeUri' in fulfillment)
conditionUri = fulfillment.serializeUri();
let jsonBody = {
'details': {}, 'details': {},
'uri': conditionUri, 'uri': conditionUri,
}; }
if (fulfillment.getTypeId() === 0) { if (fulfillment.getTypeId() === 0) {
jsonBody.details.type_id = 0; jsonBody.details.type_id = 0
jsonBody.details.bitmask = 3; jsonBody.details.bitmask = 3
if ('preimage' in fulfillment) { if ('preimage' in fulfillment) {
jsonBody.details.preimage = fulfillment.preimage.toString(); jsonBody.details.preimage = fulfillment.preimage.toString()
jsonBody.details.type = 'fulfillment'; jsonBody.details.type = 'fulfillment'
} }
} }
if (fulfillment.getTypeId() === 2) if (fulfillment.getTypeId() === 2) {
return { return {
'details': { 'details': {
'type_id': 2, 'type_id': 2,
@ -38,30 +38,31 @@ export default function ccJsonify(fulfillment) {
'bitmask': fulfillment.getBitmask(), 'bitmask': fulfillment.getBitmask(),
'threshold': fulfillment.threshold, 'threshold': fulfillment.threshold,
'subfulfillments': fulfillment.subconditions.map((subcondition) => { 'subfulfillments': fulfillment.subconditions.map((subcondition) => {
const subconditionJson = ccJsonify(subcondition.body); const subconditionJson = ccJsonify(subcondition.body)
subconditionJson.details.weight = 1; subconditionJson.details.weight = 1
return subconditionJson.details; return subconditionJson.details
}) })
}, },
'uri': conditionUri, 'uri': conditionUri,
}; }
}
if (fulfillment.getTypeId() === 4) { if (fulfillment.getTypeId() === 4) {
jsonBody.details.type_id = 4; jsonBody.details.type_id = 4
jsonBody.details.bitmask = 32; jsonBody.details.bitmask = 32
if ('publicKey' in fulfillment) { if ('publicKey' in fulfillment) {
jsonBody.details.signature = null; jsonBody.details.signature = null
jsonBody.details.public_key = base58.encode(fulfillment.publicKey); jsonBody.details.public_key = base58.encode(fulfillment.publicKey)
jsonBody.details.type = 'fulfillment'; jsonBody.details.type = 'fulfillment'
} }
} }
if ('hash' in fulfillment) { if ('hash' in fulfillment) {
jsonBody.details.hash = base58.encode(fulfillment.hash); jsonBody.details.hash = base58.encode(fulfillment.hash)
jsonBody.details.max_fulfillment_length = fulfillment.maxFulfillmentLength; jsonBody.details.max_fulfillment_length = fulfillment.maxFulfillmentLength
jsonBody.details.type = 'condition'; jsonBody.details.type = 'condition'
} }
return jsonBody; return jsonBody
} }

View File

@ -1,24 +1,24 @@
/* eslint-disable strict, no-console, object-shorthand */ /* eslint-disable strict, no-console, object-shorthand */
'use strict'; 'use strict'
const path = require('path'); const path = require('path')
const webpack = require('webpack'); const webpack = require('webpack')
const PRODUCTION = process.env.NODE_ENV === 'production'; const PRODUCTION = process.env.NODE_ENV === 'production'
const PATHS = { const PATHS = {
ENTRY: path.resolve(__dirname, './src/index.js'), ENTRY: path.resolve(__dirname, './src/index.js'),
BUNDLE: path.resolve(__dirname, 'dist/bundle'), BUNDLE: path.resolve(__dirname, 'dist/bundle'),
NODE_MODULES: path.resolve(__dirname, 'node_modules'), NODE_MODULES: path.resolve(__dirname, 'node_modules'),
}; }
/** PLUGINS **/ /** PLUGINS **/
const PLUGINS = [ const PLUGINS = [
new webpack.NoEmitOnErrorsPlugin(), new webpack.NoEmitOnErrorsPlugin(),
]; ]
const PROD_PLUGINS = [ const PROD_PLUGINS = [
new webpack.optimize.UglifyJsPlugin({ new webpack.optimize.UglifyJsPlugin({
@ -34,10 +34,10 @@ const PROD_PLUGINS = [
debug: false, debug: false,
minimize: true, minimize: true,
}), }),
]; ]
if (PRODUCTION) { if (PRODUCTION) {
PLUGINS.push(...PROD_PLUGINS); PLUGINS.push(...PROD_PLUGINS)
} }
@ -75,6 +75,6 @@ const config = {
}, },
], ],
}, },
}; }
module.exports = config; module.exports = config