@woleet/woleet-weblibs
Version:
Woleet web libraries
1,685 lines (1,374 loc) • 575 kB
JavaScript
(function(f){if(typeof exports==="object"&&typeof module!=="undefined"){module.exports=f()}else if(typeof define==="function"&&define.amd){define([],f)}else{var g;if(typeof window!=="undefined"){g=window}else if(typeof global!=="undefined"){g=global}else if(typeof self!=="undefined"){g=self}else{g=this}g.woleet = f()}})(function(){var define,module,exports;return (function(){function r(e,n,t){function o(i,f){if(!n[i]){if(!e[i]){var c="function"==typeof require&&require;if(!f&&c)return c(i,!0);if(u)return u(i,!0);var a=new Error("Cannot find module '"+i+"'");throw a.code="MODULE_NOT_FOUND",a}var p=n[i]={exports:{}};e[i][0].call(p.exports,function(r){var n=e[i][1][r];return o(n||r)},p,p.exports,r,e,n,t)}return n[i].exports}for(var u="function"==typeof require&&require,i=0;i<t.length;i++)o(t[i]);return o}return r})()({1:[function(require,module,exports){
"use strict";
function getJSON(url) {
var options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
return new Promise(function (resolve, reject) {
var req = new XMLHttpRequest();
req.onload = function () {
switch (req.status) {
case 200:
case 201:
resolve(req.response);
break;
default:
reject({ code: req.status });
break;
}
};
req.onerror = function () {
reject({ code: 0 });
};
req.open(options.method || "GET", url, true);
if (options.token) req.setRequestHeader("Authorization", 'Bearer ' + options.token);
if (options.method === 'POST') req.setRequestHeader('Content-Type', 'application/json');
req.setRequestHeader('Accept', 'application/json');
req.responseType = 'json';
req.json = 'json';
req.send(JSON.stringify(options.data));
});
}
module.exports = getJSON;
},{}],2:[function(require,module,exports){
'use strict';
if (typeof window === 'undefined') {
throw new Error('This module is not meant to be used by node');
}
var getJSON = require('./get-json');
var woleet = require('../common/woleet-api')(getJSON);
woleet.crypto = require('./woleet-crypto');
woleet.file = require('./woleet-hashfile');
woleet.receipt.validate = require('../common/woleet-chainpoint')(woleet.crypto);
woleet.signature = require('../common/woleet-signature')(woleet.identity.get);
woleet.verify = require('../common/woleet-verify')(woleet);
module.exports = woleet;
},{"../common/woleet-api":5,"../common/woleet-chainpoint":6,"../common/woleet-signature":7,"../common/woleet-verify":8,"./get-json":1,"./woleet-crypto":3,"./woleet-hashfile":4}],3:[function(require,module,exports){
(function (Buffer){(function (){
'use strict';
if (typeof _in_worker === 'undefined' && typeof window === 'undefined') {
throw new Error('This module is not meant to be used by node');
}
var CryptoJS = function (factory) {
return factory(require("crypto-js/core"), require("crypto-js/sha224"), require("crypto-js/sha256"), require("crypto-js/sha384"), require("crypto-js/sha512"), require("crypto-js/lib-typedarrays"));
}(function (CryptoJS) {
return CryptoJS;
});
var WordArray = CryptoJS.lib.WordArray;
function createSha(alg) {
var hash = CryptoJS.algo[alg].create();
var o = {};
o.update = function (data, inputEncoding) {
var _data = void 0;
if (data instanceof Uint8Array) {
_data = WordArray.create(data);
} else if (WordArray.isPrototypeOf(data)) {
_data = data;
} else if (inputEncoding) {
switch (inputEncoding) {
case 'binary':
var len = data.length;
var arr = new Uint8Array(len);
for (var i = 0; i < len; i++) {
arr[i] = data.charCodeAt(i);
}_data = WordArray.create(arr);
break;
case 'hex':
_data = CryptoJS.enc.Hex.parse(data);
break;
case 'utf8':
_data = data;
break;
case 'base64':
default:
_data = WordArray.create(new Buffer(data, inputEncoding));
}
} else if (!data) {
_data = WordArray.create();
} else if (typeof data === 'string') {
_data = data;
} else {
throw new TypeError();
}
hash.update(_data);
return o;
};
o.digest = function (encoding) {
var hex = CryptoJS.enc.Hex.stringify(hash.finalize());
if (encoding && encoding === 'hex') {
return hex;
} else {
var bin = new Buffer(hex, 'hex');
return encoding ? bin.toString(encoding) : bin;
}
};
return o;
}
function createHash(algorithm) {
switch (algorithm) {
case 'sha224':
return createSha('SHA224');
case 'sha256':
return createSha('SHA256');
case 'sha384':
return createSha('SHA384');
case 'sha512':
return createSha('SHA512');
default:
throw new Error('Hash algorithm not supported');
}
}
module.exports = {
createHash: createHash, CryptoJS: CryptoJS, Buffer: Buffer,
sha256: function sha256() {
return createHash('sha256');
},
sha224: function sha224() {
return createHash('sha224');
},
sha384: function sha384() {
return createHash('sha384');
},
sha512: function sha512() {
return createHash('sha512');
}
};
}).call(this)}).call(this,require("buffer").Buffer)
},{"buffer":20,"crypto-js/core":24,"crypto-js/lib-typedarrays":25,"crypto-js/sha224":26,"crypto-js/sha256":27,"crypto-js/sha384":28,"crypto-js/sha512":29}],4:[function(require,module,exports){
'use strict';
if (typeof window === 'undefined') {
throw new Error('This module is not meant to be used by node');
}
var isSHA256 = function isSHA256(hash) {
return (/^[a-f0-9]{64}$/i.test(hash)
);
};
var crypto = require('./woleet-crypto');
var root = window;
var isNativeCryptoSupported = root.crypto && root.crypto.subtle && root.crypto.subtle.digest;
var defaultWorkerScriptPath = function () {
var DEFAULT_WORKER_SCRIPT = "woleet-hashfile-worker.min.js";
var scripts = document.getElementsByTagName('script');
var scriptPath = scripts[scripts.length - 1].src.split('?')[0];
var basePath = scriptPath.split('/').slice(0, -1).join('/') + '/';
var wsp = root.woleet && root.woleet.workerScriptPath ? root.woleet.workerScriptPath : basePath ? basePath + DEFAULT_WORKER_SCRIPT : null;
if (!wsp) {
console.error('Cannot find Woleet WebLibs\' default worker script ' + DEFAULT_WORKER_SCRIPT);
return null;
}
console.log('Woleet WebLibs\' default worker script will be loaded from: ', wsp);
return wsp;
}();
function isFileReachable(url) {
var req = new XMLHttpRequest();
return new Promise(function (resolve) {
req.onload = function () {
return resolve(req.status === 200);
};
req.onerror = function () {
return resolve(false);
};
req.open("GET", url, true);
req.send();
}).catch(function () {
return false;
});
}
function Hasher(wsp) {
if (!wsp) wsp = defaultWorkerScriptPath;
var ready = true;
var cancel = null;
var skip = null;
var _events = {};
var EVT_START = 'start',
EVT_PROGRESS = 'progress',
EVT_ERROR = 'error',
EVT_RESULT = 'result',
EVT_CANCEL = 'cancel',
EVT_SKIP = 'skip';
var emit = function emit(event, data) {
return _events[event] && _events[event](data);
};
var emittable = function emittable(event) {
return _events[event];
};
var _onCancel = function _onCancel(cb) {
return cancel = cb;
};
var _onSkip = function _onSkip(cb) {
return skip = cb;
};
var CANCEL_EXCEPTION = '__cancel__';
var SKIP_EXCEPTION = '__skip__';
var HASH_LOCAL_LIMIT = 134217728;
var HASH_NATIVE_LIMIT = 1073741824;
function HashWorker(wsp) {
var worker = new Worker(wsp);
this.hash = function (file) {
return new Promise(function (next, reject) {
var cancelled = false;
var skipped = false;
var reader = new FileReader();
_onCancel(function () {
cancelled = true;
worker.terminate();
reader.abort();
worker = null;
emit(EVT_CANCEL, { file: file });
reject(CANCEL_EXCEPTION);
});
_onSkip(function () {
skipped = true;
reader.abort();
worker.postMessage({ action: 'reset' });
});
var min = function min(a, b) {
return a > b ? b : a;
};
var bufferSize = 0xfffff,
fileSize = file.size;
var start = 0,
stop = 0;
worker.onmessage = function (event) {
if (cancelled) {
return;
} else if (event.data.reset) {
emit(EVT_SKIP, { file: file });
reject(SKIP_EXCEPTION);
return;
} else if (skipped) {
return;
} else if (event.data.result) {
emit(EVT_RESULT, { result: event.data.result, file: file });
return next();
} else if (event.data.error) {
var message = event.data.error;
reader.abort();
if (emittable(EVT_ERROR)) emit(EVT_ERROR, { error: new Error(message), file: file });else return reject(new Error(message));
} else if (event.data.start) {
emit(EVT_START, { start: event.data.start, file: file });
} else if (event.data.progress) {
emit(EVT_PROGRESS, { progress: stop / fileSize, file: file });
} else {
console.trace("Unexpected worker message: ", event);
}
if (stop !== fileSize) {
start = stop;
stop = min(stop + bufferSize, fileSize);
reader.readAsArrayBuffer(file.slice(start, stop));
} else {
worker.postMessage({ action: 'finalize' });
}
};
reader.onload = function (event) {
worker.postMessage({
chunk: event.target.result,
action: 'update'
});
};
worker.postMessage({ action: 'start' });
});
};
this.worker = worker;
}
function checkFileSize(file, limit, reject) {
if (file.size > limit) {
ready = true;
var error = new Error("file_too_big_to_be_hashed_without_worker");
if (emittable(EVT_ERROR)) return emit(EVT_ERROR, { error: error, file: file });else reject(error);
return false;
}
return true;
}
function hashLocal(file) {
return new Promise(function (next, reject) {
if (!checkFileSize(file, HASH_LOCAL_LIMIT, reject)) return;
var prev = 0;
var cancelled = false;
var skipped = false;
var report_update = false;
var sha256 = crypto.sha256();
var reader = new FileReader();
function update(buffer, loaded) {
var blob = buffer.slice(prev, loaded);
var chunkUint8 = new Uint8Array(blob);
sha256.update(chunkUint8);
prev = loaded;
}
_onCancel(function () {
cancelled = true;
reader.abort();
emit(EVT_CANCEL, { file: file });
});
_onSkip(function () {
skipped = true;
reader.abort();
emit(EVT_SKIP, { file: file });
});
reader.onloadstart = function () {
if (cancelled || skipped) return;
emit(EVT_START, { start: true, file: file });
};
reader.onload = function (event) {
if (cancelled || skipped) return;
if (report_update) {
update(event.target.result, event.loaded, event.total);
}
var result = sha256.digest('hex');
emit(EVT_RESULT, { result: result, file: file });
next();
};
reader.onprogress = function (event) {
if (cancelled || skipped) return;
var data = event.target.result;
emit(EVT_PROGRESS, { progress: event.loaded / event.total, file: file });
if (!data) return report_update = true;
update(data, event.loaded, event.total);
};
reader.onabort = function () {
if (cancelled) {
reject(CANCEL_EXCEPTION);
} else if (skipped) {
reject(SKIP_EXCEPTION);
} else {
reject(new Error('Unhandled abort exception'));
}
};
reader.readAsArrayBuffer(file);
});
}
function hashLocalWithNativeAPI(file) {
return new Promise(function (resolve, reject) {
if (!checkFileSize(file, HASH_NATIVE_LIMIT, reject)) return;
var alg = "SHA-256";
var cancelled = false;
var skipped = false;
var reader = new FileReader();
_onCancel(function () {
cancelled = true;
reader.abort();
emit(EVT_CANCEL, { file: file });
});
_onSkip(function () {
skipped = true;
reader.abort();
emit(EVT_SKIP, { file: file });
});
reader.onloadstart = function () {
if (cancelled || skipped) return;
emit(EVT_START, { start: true, file: file });
};
reader.onprogress = function (event) {
if (cancelled || skipped) return;
emit(EVT_PROGRESS, { progress: event.loaded / event.total, file: file });
};
reader.onload = function (event) {
if (cancelled || skipped) return;
var data = event.target.result;
root.crypto.subtle.digest(alg, data).then(function (hash) {
if (cancelled || skipped) return;
var hashResult = new Uint8Array(hash);
var result = hashResult.reduce(function (res, e) {
return res + ('00' + e.toString(16)).slice(-2);
}, '');
emit(EVT_RESULT, { result: result, file: file });
resolve();
}).catch(function (error) {
return _events[EVT_ERROR] ? emit(EVT_ERROR, { error: error, file: file }) : reject(error);
});
};
reader.onabort = function () {
if (cancelled) {
reject(CANCEL_EXCEPTION);
} else if (skipped) {
reject(SKIP_EXCEPTION);
} else {
reject(new Error('Unhandled abort exception'));
}
};
reader.readAsArrayBuffer(file);
});
}
this.on = function (event, callback) {
switch (event) {
case EVT_START:
case EVT_PROGRESS:
case EVT_ERROR:
case EVT_RESULT:
case EVT_SKIP:
case EVT_CANCEL:
_events[event] = callback;
break;
default:
throw new Error('Invalid event name "' + event + '"');
}
};
this.start = function (files) {
var hashWorker = null;
if (!ready) throw new Error("not_ready");
ready = false;
if (!(files instanceof FileList || files instanceof File || Array.isArray(files) && files.every(function (file) {
return file instanceof File;
}))) throw new Error("invalid_parameter");
var isWorkerSupportedPromise =
function () {
if (!wsp) return Promise.resolve(false);
var workerReachablePromise = isFileReachable(wsp);
var cryptoReachablePromise = isFileReachable(wsp.split('/').slice(0, -1).join('/') + '/woleet-crypto.min.js');
function makeWorker(script) {
var URL = root.URL || window.webkitURL;
var Blob = root.Blob;
var Worker = root.Worker;
if (!URL || !Blob || !Worker || !script) return null;
var blob = new Blob([script]);
return new Worker(URL.createObjectURL(blob));
}
var workerSupportedPromise = new Promise(function (resolve) {
var syncDetectionScript = "onmessage = function(e) { postMessage(!!FileReaderSync); close() };";
try {
var worker = makeWorker(syncDetectionScript);
if (worker) {
worker.onmessage = function (e) {
worker.terminate();
worker = null;
resolve(e.data);
};
worker.postMessage({});
} else {
resolve(false);
}
} catch (error) {
resolve(false);
}
});
return Promise.all([workerReachablePromise, cryptoReachablePromise, workerSupportedPromise]).then(function (arr) {
return arr.every(function (e) {
return true === e;
});
});
}().then(function (support) {
if (!support) console.warn('Failed to load worker.');
return support;
});
isWorkerSupportedPromise.then(function (workerSupported) {
function iter(i, len, files) {
if (i >= len) {
ready = true;
if (hashWorker && hashWorker.worker) {
hashWorker.worker.terminate();
hashWorker.worker = null;
}
return Promise.resolve();
} else {
var hashMethod = void 0;
if (files[i].size === 0) {
hashMethod = hashLocal;
} else if (isNativeCryptoSupported && files[i].size <= HASH_NATIVE_LIMIT) {
hashMethod = hashLocalWithNativeAPI;
} else if (workerSupported && files[i].size > HASH_LOCAL_LIMIT) {
if (!hashWorker) hashWorker = new HashWorker(wsp);
hashMethod = hashWorker.hash;
} else {
hashMethod = hashLocal;
}
return hashMethod(files[i]).then(function () {
return iter(i + 1, len, files);
}).catch(function (error) {
if (error === SKIP_EXCEPTION) return iter(i + 1, len, files);
if (error !== CANCEL_EXCEPTION) throw error;
});
}
}
if (files instanceof FileList) {
return iter(0, files.length, files);
} else if (files instanceof File) {
return iter(0, 1, [files]);
} else {
return iter(0, files.length, files);
}
});
};
this.cancel = function () {
if (cancel) {
cancel();
cancel = null;
ready = true;
}
};
this.skip = function () {
if (cancel) {
skip();
skip = null;
}
};
this.isReady = function () {
return ready;
};
}
function hashFileOrCheckHash(file, progressCallback) {
return new Promise(function (resolve, reject) {
if (file instanceof File) {
var hasher = new Hasher();
hasher.on('result', function (message, file) {
resolve(message.result);
if (progressCallback) progressCallback({ progress: 1.0, file: file });
});
if (progressCallback && typeof progressCallback === 'function') hasher.on('progress', progressCallback);
hasher.on('error', reject);
hasher.start(file);
}
else if (typeof file === 'string') {
if (isSHA256(file)) resolve(file);else reject(new Error("parameter_string_not_a_sha256_hash"));
}
else reject(new Error("invalid_parameter"));
});
}
module.exports = { Hasher: Hasher, hashFileOrCheckHash: hashFileOrCheckHash };
},{"./woleet-crypto":3}],5:[function(require,module,exports){
'use strict';
var _slicedToArray = function () { function sliceIterator(arr, i) { var _arr = []; var _n = true; var _d = false; var _e = undefined; try { for (var _i = arr[Symbol.iterator](), _s; !(_n = (_s = _i.next()).done); _n = true) { _arr.push(_s.value); if (i && _arr.length === i) break; } } catch (err) { _d = true; _e = err; } finally { try { if (!_n && _i["return"]) _i["return"](); } finally { if (_d) throw _e; } } return _arr; } return function (arr, i) { if (Array.isArray(arr)) { return arr; } else if (Symbol.iterator in Object(arr)) { return sliceIterator(arr, i); } else { throw new TypeError("Invalid attempt to destructure non-iterable instance"); } }; }();
module.exports = function (getJSON) {
var woleet = { receipt: {}, identity: {} };
function dataToURI(data) {
if (!data || Object.keys(data).length === 0) return '';
var _data = [];
for (var prop in data) {
if (data[prop]) _data.push([encodeURIComponent(prop), encodeURIComponent(data[prop])].join('='));
}
return "?" + _data.join('&');
}
function makeTransaction(txId, confirmations, timestamp, blockHash, opReturn) {
if (timestamp.toString() === 'Invalid Date') timestamp = null;
return {
txId: txId,
confirmations: confirmations,
timestamp: timestamp,
blockHash: blockHash,
opReturn: opReturn
};
}
var DEFAULT_WOLEET_API_URL = "https://api.woleet.io/v1";
var woleetApiUrl = DEFAULT_WOLEET_API_URL;
var DEFAULT_TRANSACTION_PROVIDER = 'woleet.io';
var transactionProvider = DEFAULT_TRANSACTION_PROVIDER;
woleet.config = {
setDefaultTransactionProvider: function setDefaultTransactionProvider(_transactionProvider) {
switch (_transactionProvider) {
case 'blockcypher.com':
case 'blockstream.info':
case 'woleet.io':
transactionProvider = _transactionProvider;
break;
default:
transactionProvider = DEFAULT_TRANSACTION_PROVIDER;
break;
}
},
setDefaultWoleetApiUrl: function setDefaultWoleetApiUrl(_woleetApiUrl) {
woleetApiUrl = _woleetApiUrl;
}
};
woleet.transaction = {
get: function get(txId) {
switch (transactionProvider) {
case 'woleet.io':
return getJSON(woleetApiUrl + '/bitcoin/transaction/' + txId).then(function (tx) {
if (!tx.time || !tx.confirmations) {
throw new Error('tx_not_confirmed');
}
return makeTransaction(tx.txid, tx.confirmations, new Date(tx.time * 1000), tx.blockhash, function (output) {
return output ? output.scriptPubKey.asm.split(' ')[1] : null;
}((tx.vout || []).find(function (o) {
return o.hasOwnProperty('scriptPubKey') && o.scriptPubKey.hasOwnProperty('asm') && o.scriptPubKey.asm.startsWith('OP_RETURN');
})));
}).catch(function () {
throw new Error('tx_not_found');
});
case 'blockstream.info':
return getJSON('https://blockstream.info/api/tx/' + txId).then(function (tx) {
if (!tx.status.block_hash) {
throw new Error('tx_not_confirmed');
}
return getJSON('https://blockstream.info/api/blocks/tip/height').then(function (tipHeight) {
return getJSON('https://blockstream.info/api/block/' + tx.status.block_hash).then(function (block) {
return makeTransaction(txId, tipHeight - block.height, new Date(block.timestamp * 1000), block.id, function (output) {
return output ? output.scriptpubkey_asm.split(' ')[2] : null;
}((tx.vout || []).find(function (o) {
return o.hasOwnProperty('scriptpubkey') && o.scriptpubkey_asm && o.scriptpubkey_asm.startsWith('OP_RETURN');
})));
}).catch(function (error) {
throw new Error('Failed to get block');
});
}).catch(function (error) {
throw new Error('Failed to get current block height');
});
}).catch(function (error) {
throw new Error('tx_not_found');
});
case 'blockcypher.com':
return getJSON('https://api.blockcypher.com/v1/btc/main/txs/' + txId).then(function (tx) {
if (tx.error) {
throw new Error('tx_not_found');
}
if (!tx.confirmed || !tx.confirmations) {
throw new Error('tx_not_confirmed');
}
return makeTransaction(tx.hash, tx.confirmations, new Date(tx.confirmed), tx.block_hash, function (output) {
return output ? output.data_hex : null;
}((tx.outputs || []).find(function (o) {
return o.hasOwnProperty('data_hex');
})));
}).catch(function () {
throw new Error('tx_not_found');
});
}
}
};
var _types = {
DATA: 1,
SIGNATURE: 2,
BOTH: 3
};
woleet.anchor = {
types: _types,
getAnchorIDs: function getAnchorIDs(hash, type, size) {
switch (type) {
case _types.SIGNATURE:
return getJSON(woleetApiUrl + '/anchorids' + dataToURI({ signedHash: hash, size: size })).then(function (res) {
return res.content || [];
}).catch(function (error) {
throw new Error('http_error');
});
case _types.DATA:
return getJSON(woleetApiUrl + '/anchorids' + dataToURI({ hash: hash, size: size })).then(function (res) {
return res.content || [];
}).catch(function (error) {
throw new Error('http_error');
});
case _types.BOTH:
default:
var a = woleet.anchor.getAnchorIDs(hash, _types.SIGNATURE, size);
var b = woleet.anchor.getAnchorIDs(hash, _types.DATA, size);
return Promise.all([a, b]).then(function (_ref) {
var _ref2 = _slicedToArray(_ref, 2),
a = _ref2[0],
b = _ref2[1];
if (a instanceof Error || b instanceof Error) throw new Error('http_error');
return [].concat(a, b);
});
}
}
};
woleet.receipt.get = function (anchorId) {
return getJSON(woleetApiUrl + "/receipt/" + anchorId).catch(function (error) {
if (error.code === 404) throw new Error('not_found');else throw new Error(error.code);
});
};
woleet.identity.get = function (identityUrl, pubKey, signedIdentity, leftData) {
return getJSON(identityUrl + dataToURI({ pubKey: pubKey, signedIdentity: signedIdentity, leftData: leftData })).catch(function (error) {
if (error.code === 404) {
throw new Error('key_not_found');
} else if (error.code === 400 || error.code === 0) {
throw new Error('http_error');
} else {
throw new Error(error.code);
}
});
};
woleet.isSHA256 = function (hash) {
return (/^[a-f0-9]{64}$/i.test(hash)
);
};
woleet.getJSON = getJSON;
return woleet;
};
},{}],6:[function(require,module,exports){
'use strict';
var _typeof = typeof Symbol === "function" && typeof Symbol.iterator === "symbol" ? function (obj) { return typeof obj; } : function (obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; };
module.exports = function (crypto) {
var INVALID_RECEIPT_FORMAT = 'invalid_receipt_format',
INVALID_TARGET_PROOF = 'invalid_target_proof',
INVALID_TYPE = 'invalid_type',
NON_SHA256_TARGET_PROOF_ELEMENT = 'non_sha256_target_proof_element',
MERKLE_ROOT_MISMATCH = 'merkle_root_mismatch',
INVALID_PARENT_IN_PROOF_ELEMENT = 'invalid_parent_in_proof_element',
UNSUPPORTED_ALGORITHM = 'unsupported_algorithm';
var isHex = function isHex(len) {
var reg = new RegExp('^[a-f0-9]{' + len + '}$', 'i');
return function (hash) {
return reg.test(hash);
};
};
var isSHA256 = isHex(64);
var sha224 = crypto.sha224;
var sha256 = crypto.sha256;
var sha384 = crypto.sha384;
var sha512 = crypto.sha512;
function MerkleProof(target) {
var self = this;
this.branches = [];
this.target = target;
this.add = function (branch) {
self.branches.push(branch);
};
this.is_valid = function (root) {
var target = self.target;
if (!self.branches.length) return false;
for (var i = 0, branch; i < self.branches.length; i++) {
branch = self.branches[i];
if (!(target === branch.left || target === branch.right)) {
return false;
}
target = branch.parent;
}
return target.toLowerCase() === root.toLowerCase();
};
this.getJSON = function () {
return self.branches.map(function (branch) {
return branch.getJSON();
});
};
}
function hasAllProperties(obj) {
for (var _len = arguments.length, props = Array(_len > 1 ? _len - 1 : 0), _key = 1; _key < _len; _key++) {
props[_key - 1] = arguments[_key];
}
var _iteratorNormalCompletion = true;
var _didIteratorError = false;
var _iteratorError = undefined;
try {
for (var _iterator = props[Symbol.iterator](), _step; !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = true) {
var prop = _step.value;
if (prop instanceof Array) {
if (!obj.hasOwnProperty(prop[0])) return false;else if (typeof prop[1] === 'string') {
if (!(_typeof(obj[prop[0]]) === prop[1])) return false;
} else {
if (!(obj[prop[0]] instanceof prop[1])) return false;
}
} else {
if (!obj.hasOwnProperty(prop) || typeof obj[prop] !== 'string') {
return false;
}
}
}
} catch (err) {
_didIteratorError = true;
_iteratorError = err;
} finally {
try {
if (!_iteratorNormalCompletion && _iterator.return) {
_iterator.return();
}
} finally {
if (_didIteratorError) {
throw _iteratorError;
}
}
}
return true;
}
function _validateChainpoint1Receipt(receipt) {
if (!hasAllProperties(receipt, ['header', 'object'], ['target', 'object'])) throw new Error(INVALID_RECEIPT_FORMAT);
if (!hasAllProperties(receipt.header, 'chainpoint_version', 'hash_type', 'merkle_root', 'tx_id', ['timestamp', 'number'])) throw new Error(INVALID_RECEIPT_FORMAT);
if (!hasAllProperties(receipt.target, 'target_hash', ['target_proof', Array])) throw new Error(INVALID_RECEIPT_FORMAT);
if (!receipt.target.target_proof.every(function (branch) {
return hasAllProperties(branch, 'left', 'right', 'parent');
})) throw new Error(INVALID_TARGET_PROOF);
if (!receipt.target.target_proof.every(function (branch) {
return isSHA256(branch.left) && isSHA256(branch.right) && isSHA256(branch.parent);
})) throw new Error(NON_SHA256_TARGET_PROOF_ELEMENT);
if (receipt.target.target_proof.length === 0) {
if (receipt.target.target_hash.toLowerCase() === receipt.header.merkle_root.toLowerCase()) return true;else throw new Error(MERKLE_ROOT_MISMATCH);
}
else {
var proof = new MerkleProof(receipt.target.target_hash);
receipt.target.target_proof.forEach(function (branch) {
var parent = sha256().update(branch.left + branch.right, 'utf8').digest('hex');
if (parent !== branch.parent) {
throw new Error(INVALID_PARENT_IN_PROOF_ELEMENT);
}
proof.add({ left: branch.left, right: branch.right, parent: parent });
});
if (proof.is_valid(receipt.header.merkle_root)) return true;else throw new Error(MERKLE_ROOT_MISMATCH);
}
}
function _validateChainpoint2Receipt(receipt) {
if (!hasAllProperties(receipt, 'targetHash', 'merkleRoot', ['proof', Array], ['anchors', Array])) {
throw new Error(INVALID_RECEIPT_FORMAT);
}
if (!(receipt.hasOwnProperty('@context') || receipt.hasOwnProperty('context') && receipt.hasOwnProperty('@type') || receipt.hasOwnProperty('type'))) {
throw new Error(INVALID_RECEIPT_FORMAT);
}
var type = receipt.type || receipt['@type'];
if (typeof type !== 'string' || !/^ChainpointSHA([0-9]-)?[0-9]{3}v2$/.test(type)) {
throw new Error(INVALID_RECEIPT_FORMAT);
}
var shaX = null;
var validateHex = null;
switch (type) {
case "ChainpointSHA224v2":
shaX = sha224;
validateHex = isHex(56);
break;
case "ChainpointSHA256v2":
shaX = sha256;
validateHex = isHex(64);
break;
case "ChainpointSHA384v2":
shaX = sha384;
validateHex = isHex(96);
break;
case "ChainpointSHA512v2":
shaX = sha512;
validateHex = isHex(128);
break;
case "ChainpointSHA3-224v2":
case "ChainpointSHA3-256v2":
case "ChainpointSHA3-384v2":
case "ChainpointSHA3-512v2":
throw new Error(UNSUPPORTED_ALGORITHM);
default:
throw new Error(INVALID_TYPE);
}
var xor = function xor(a, b) {
return a ? !b : b;
};
if (!receipt.proof.every(function (branch) {
return xor(branch.hasOwnProperty('left'), branch.hasOwnProperty('right'));
})) throw new Error(INVALID_TARGET_PROOF);
if (!receipt.proof.every(function (branch) {
return validateHex(branch.left || branch.right);
})) throw new Error(NON_SHA256_TARGET_PROOF_ELEMENT);
if (receipt.proof.length === 0) {
if (receipt.targetHash.toLowerCase() === receipt.merkleRoot.toLowerCase()) return true;else throw new Error(MERKLE_ROOT_MISMATCH);
}
else {
var proof = new MerkleProof(receipt.targetHash);
var target = receipt.targetHash;
receipt.proof.forEach(function (branch) {
var left = void 0,
right = void 0;
if (branch.left) {
left = branch.left;
right = target;
} else {
left = target;
right = branch.right;
}
var parent = shaX().update(left + right, 'hex').digest('hex');
target = parent;
proof.add({ left: left, right: right, parent: parent });
});
if (proof.is_valid(receipt.merkleRoot)) return true;else throw new Error(MERKLE_ROOT_MISMATCH);
}
}
function validateReceipt(receipt) {
if (!receipt || (typeof receipt === 'undefined' ? 'undefined' : _typeof(receipt)) !== 'object') throw new Error(INVALID_RECEIPT_FORMAT);
if (receipt.hasOwnProperty('header')) {
return _validateChainpoint1Receipt(receipt);
} else {
return _validateChainpoint2Receipt(receipt);
}
}
return validateReceipt;
};
},{}],7:[function(require,module,exports){
(function (Buffer){(function (){
'use strict';
var _typeof = typeof Symbol === "function" && typeof Symbol.iterator === "symbol" ? function (obj) { return typeof obj; } : function (obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; };
module.exports = function (getIdentity) {
var messagePrefix = '\x18Bitcoin Signed Message:\n';
var verify = require('bitcoinjs-message').verify;
function checkIdentities(identity, signedIdentity) {
if (!signedIdentity) return {
valid: true,
identity: identity
};
signedIdentity = deserializeX500DN(signedIdentity);
if (signedIdentity.commonName !== identity.commonName || signedIdentity.emailAddress && identity.emailAddress && signedIdentity.emailAddress !== identity.emailAddress) {
return {
valid: false,
reason: "identity_mismatch"
};
}
return {
valid: true,
identity: identity,
signedIdentity: signedIdentity
};
}
function deserializeX500DN(x500dn) {
function splitUnescaped(delim, str) {
var result = [];
var previousChar = void 0;
var start = 0;
for (var i = 0; i < str.length; i++) {
var currentChar = str.charAt(i);
if (currentChar === delim && previousChar !== '\\') {
result.push(str.slice(start, i));
i++;
start = i;
}
if (i >= str.length - 1) {
result.push(str.slice(start, i + 1));
}
previousChar = currentChar;
}
return result;
}
var identity = {};
var attrs = splitUnescaped(',', x500dn);
attrs.forEach(function (attr) {
var keyValue = splitUnescaped('=', attr);
var key = keyValue[0];
var value = keyValue[1].replace("\\ ", " ")
.replace("\\=", "=")
.replace("\\\"", "\"")
.replace("\\,", ",")
.replace("\\;", ";")
.replace("\\+", "+");
switch (key.toUpperCase().trim()) {
case 'CN':
identity.commonName = value;
break;
case 'EMAILADDRESS':
identity.emailAddress = value;
break;
case 'O':
identity.organization = value;
break;
case 'OU':
identity.organizationalUnit = value;
break;
case 'L':
identity.locality = value;
break;
case 'C':
identity.country = value;
break;
}
});
return identity;
}
function randomString(len) {
var l = 0;
var a = [];
while (l++ < len) {
a.push(Math.floor(Math.random() * 0xff));
}return new Buffer(a).toString('hex');
}
function validateIdentity(identityUrl, pubKey, signedIdentity, signedIssuerDomain) {
if (!identityUrl) {
if (!signedIdentity) {
return Promise.resolve({
valid: false
});
}
return Promise.resolve({
valid: true,
signedIdentity: deserializeX500DN(signedIdentity)
});
}
if (signedIssuerDomain && !new URL(identityUrl).hostname.includes(signedIssuerDomain)) {
return Promise.resolve({
valid: false,
reason: "identity_mismatch"
});
}
var leftData = randomString(16);
return getIdentity(identityUrl, pubKey, signedIdentity, leftData).then(function (identity) {
if (!identity || (typeof identity === 'undefined' ? 'undefined' : _typeof(identity)) != 'object') {
return {
valid: false,
reason: "invalid response"
};
}
if (!identity.signature) {
if (!identity.identity) {
return {
valid: false,
reason: "'identity' should be provided'"
};
}
return checkIdentities(identity.identity, signedIdentity);
}
else {
if (!identity.rightData.startsWith(identityUrl)) {
return {
valid: false,
reason: '\'rightData\' should start with \'' + identityUrl + '\''
};
}
return validateSignature(leftData + identity.rightData, pubKey, identity.signature).then(function (result) {
if (!result.valid) {
return result;
}
return checkIdentities(identity.identity, signedIdentity);
});
}
})
.catch(function (error) {
if (error.message === 'key_not_found') {
return {
valid: false,
reason: error.message
};
}
if (!signedIdentity) {
return Promise.resolve({
valid: false,
reason: error.message
});
}
return Promise.resolve({
valid: true,
signedIdentity: deserializeX500DN(signedIdentity)
});
});
}
function validateSignature(message, address, signature) {
try {
return Promise.resolve({ valid: verify(message, address, signature, messagePrefix) });
} catch (error) {
return Promise.resolve({ valid: false, reason: error.message });
}
}
return { validateSignature: validateSignature, validateIdentity: validateIdentity, deserializeX500DN: deserializeX500DN };
};
}).call(this)}).call(this,require("buffer").Buffer)
},{"bitcoinjs-message":13,"buffer":20}],8:[function(require,module,exports){
"use strict";
module.exports = function (woleet) {
function validateSignatureAndIdentity(verification) {
return Promise.resolve(verification).then(function (verification) {
var s = verification.receipt.signature;
if (!s) {
return verification;
}
if (!s.signature || !s.signedHash || !s.pubKey) {
throw new Error('invalid_receipt_signature_format');
}
var message = s.signedHash;
if (s.signedIdentity || s.signedIssuerDomain) {
message = woleet.crypto.sha256().update(s.signedHash + (s.signedIdentity || "") + (s.signedIssuerDomain || "")).digest('hex');
}
return woleet.signature.validateSignature(message, s.pubKey, s.signature).then(function (res) {
if (!res.valid) {
throw new Error('invalid_receipt_signature');
}
return woleet.signature.validateIdentity(s.identityURL, s.pubKey, s.signedIdentity, s.signedIssuerDomain).then(function (res) {
if (!res.valid) {
verification.identityVerificationStatus = {
code: res.reason,
identity: res.identity,
signedIdentity: res.signedIdentity
};
} else {
verification.identityVerificationStatus = {
code: 'verified',
identity: res.identity,
signedIdentity: res.signedIdentity
};
}
return verification;
}).catch(function (error) {
verification.identityVerificationStatus = {
code: error.message
};
return verification;
});
});
});
}
function validateTransaction(receipt) {
var getReceiptTxId = function getReceiptTxId(receipt) {
return receipt.header && receipt.header.tx_id || receipt.anchors && receipt.anchors.find(function (e) {
return e.type === "BTCOpReturn";
}).sourceId;
};
return woleet.transaction.get(getReceiptTxId(receipt)).then(function (tx) {
if (tx.opReturn === (receipt.header && receipt.header.merkle_root || receipt.merkleRoot)) {
return {
receipt: receipt,
confirmations: tx.confirmations,
timestamp: tx.timestamp,
code: 'verified'
};
} else {
throw new Error('op_return_mismatches_merkle_root');
}
});
}
function compareTargetHash(receipt, hash) {
if (receipt.signature) {
if (receipt.signature.signedHash !== hash) {
throw new Error("target_hash_mismatch");
}
} else {
if ((receipt.target && receipt.target.target_hash || receipt.targetHash) !== hash) {
throw new Error("target_hash_mismatch");
}
}
}
function WoleetDAB(file, progressCallback) {
return woleet.file.hashFileOrCheckHash(file, progressCallback)
.then(function (hash) {
return woleet.anchor.getAnchorIDs(hash, woleet.anchor.types.BOTH);
})
.then(function (anchorIDArray) {
var receiptArray = [];
return anchorIDArray.reduce(function (chain, anchorId) {
return chain.then(function () {
return woleet.receipt.get(anchorId).then(function (receipt) {
receiptArray.push(receipt);
}).catch(function (error) {
if (error.message !== '202') {
throw error;
}
});
});
}, Promise.resolve())
.then(function () {
if (anchorIDArray.length && !receiptArray.length) {
throw new Error('file_matched_but_anchor_not_yet_processed');
}
return receiptArray;
});
})
.then(function (receiptArray) {
var finalArray = [];
return receiptArray.reduce(function (chain, receipt) {
return chain.then(function () {
return verifyReceipt(receipt).then(function (validation) {
finalArray.push(validation);
}).catch(function (error) {
finalArray.push({ receipt: receipt, code: error.message });
});
});
}, Promise.resolve())
.then(function () {
return finalArray.sort(function (a, b) {
if (!a.timestamp) return 1;
if (!b.timestamp) return -1;
if (a.timestamp && b.timestamp) {
return a.timestamp.getTime() - b.timestamp.getTime();
}
return 0;
});
});
});
}
function DAB(file, receipt, progressCallback) {
return woleet.file.hashFileOrCheckHash(file, progressCallback).then(function (hash) {
return verifyReceipt(receipt, hash);
});
}
function verifyReceipt(receipt, hash) {
return Promise.resolve().then(function () {
return woleet.receipt.validate(receipt);
}).then(function () {
if (hash) compareTargetHash(receipt, hash);
}).then(function () {
return validateTransaction(receipt);
}).then(validateSignatureAndIdentity).catch(function (error) {
return { receipt: receipt, code: error.message };
});
}
return {
WoleetDAB: WoleetDAB,
DAB: DAB,
receipt: verifyReceipt
};
};
},{}],9:[function(require,module,exports){
'use strict'
var _Buffer = require('safe-buffer').Buffer
function base (ALPHABET) {
if (ALPHABET.length >= 255) { throw new TypeError('Alphabet too long') }
var BASE_MAP = new Uint8Array(256)
for (var j = 0; j < BASE_MAP.length; j++) {
BASE_MAP[j] = 255
}
for (var i = 0; i < ALPHABET.length; i++) {
var x = ALPHABET.charAt(i)
var xc = x.charCodeAt(0)
if (BASE_MAP[xc] !== 255) { throw new TypeError(x + ' is ambiguous') }
BASE_MAP[xc] = i
}
var BASE = ALPHABET.length
var LEADER = ALPHABET.charAt(0)
var FACTOR = Math.log(BASE) / Math.log(256)
var iFACTOR = Math.log(256) / Math.log(BASE)
function encode (source) {
if (Array.isArray(source) || source instanceof Uint8Array) { source = _Buffer.from(source) }
if (!_Buffer.isBuffer(source)) { throw new TypeError('Expected Buffer') }
if (source.length === 0) { return '' }
var zeroes = 0
var length = 0
var pbegin = 0
var pend = source.length
while (pbegin !== pend && source[pbegin] === 0) {
pbegin++
zeroes++
}
var size = ((pend - pbegin) * iFACTOR + 1) >>> 0
var b58 = new Uint8Array(size)
while (pbegin !== pend) {
var carry = source[pbegin]
var i = 0
for (var it1 = size - 1; (carry !== 0 || i < length) && (it1 !== -1); it1--, i++) {
carry += (256 * b58[it1]) >>> 0
b58[it1] = (carry % BASE) >>> 0
carry = (carry / BASE) >>> 0
}
if (carry !== 0) { throw new Error('Non-zero carry') }
length = i
pbegin++
}
var it2 = size - length
while (it2 !== size && b58[it2] === 0) {
it2++
}
var str = LEADER.repeat(zeroes)
for (; it2 < size; ++it2) { str += ALPHABET.charAt(b58[it2]) }
return str
}
function decodeUnsafe (source) {
if (typeof source !== 'string') { throw new TypeError('Expected String') }
if (source.length === 0) { return _Buffer.alloc(0) }
var psz = 0
var zeroes = 0
var length = 0
while (source[psz] === LEADER) {
zeroes++
psz++
}
var size = (((source.length - psz) * FACTOR) + 1) >>> 0
var b256 = new Uint8Array(size)
while (source[psz]) {
var carry = BASE_MAP[source.charCodeAt(psz)]
if (carry === 255) { return }
var i = 0
for (var it3 = size - 1; (carry !== 0 || i < length) && (it3 !== -1); it3--, i++) {
carry += (BASE * b256[it3]) >>> 0
b256[it3] = (carry % 256) >>> 0
carry = (carry / 256) >>> 0
}
if (carry !== 0) { throw new Error('Non-zero carry') }
length = i
psz++
}
var it4 = size - length
while (it4 !== size && b256[it4] === 0) {
it4++
}
var vch = _Buffer.allocUnsafe(zeroes + (size - it4))
vch.fill(0x00, 0, zeroes)
var j = zeroes
while (it4 !== size) {
vch[j++] = b256[it4++]
}
return vch
}
function decode (string) {
var buffer = decodeUnsafe(string)
if (buffer) { return buffer }
throw new Error('Non-base' + BASE + ' character')
}
return {
encode: encode,
decodeUnsafe: decodeUnsafe,
decode: decode
}
}
module.exports = base
},{"safe-buffer":103}],10:[function(require,module,exports){
'use strict'
exports.byteLength = byteLength
exports.toByteArray = toByteArray
exports.fromByteArray = fromByteArray
var lookup = []
var revLookup = []
var Arr = typeof Uint8Array !== 'undefined' ? Uint8Array : Array
var code = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/'
for (var i = 0, len = code.length; i < len; ++i) {
lookup[i] = code[i]
revLookup[code.charCodeAt(i)] = i
}
revLookup['-'.charCodeAt(0)] = 62
revLookup['_'.charCodeAt(0)] = 63
function getLens (b64) {
var len = b64.length
if (len % 4 > 0) {
throw new Error('Invalid string. Length must be a multiple of 4')
}
var validLen = b64.indexOf('=')
if (validLen === -1) validLen = len
var placeHoldersLen = validLen === len
? 0
: 4 - (validLen % 4)
return [validLen, placeHoldersLen]
}
function byteLength (b64) {
var lens = getLens(b64)
var validLen = lens[0]
var placeHoldersLen = lens[1]
return ((validLen + placeHoldersLen) * 3 / 4) - placeHoldersLen
}
function _byteLength (b64, validLen, placeHoldersLen) {
return ((validLen + placeHoldersLen) * 3 / 4) - placeHoldersLen
}
function toByteArray (b64) {
var tmp
var lens = getLens(b64)
var validLen = lens[0]
var placeHoldersLen = lens[1]
var arr = new Arr(_byteLength(b64, validLen, placeHoldersLen))
var curByte = 0
var len = placeHoldersLen > 0
? validLen - 4
: validLen
var i
for (i = 0; i < len; i += 4) {
tmp =
(revLookup[b64.charCodeAt(i)] << 18) |
(revLookup[b64.charCodeAt(i + 1)] << 12) |
(revLookup[b64.charCodeAt(i + 2)] << 6) |
revLookup[b64.charCodeAt(i + 3)]
arr[curByte++] = (tmp >> 16) & 0xFF
arr[curByte++] = (tmp >> 8) & 0xFF
arr[curByte++] = tmp & 0xFF
}
if (placeHoldersLen === 2) {
tmp =
(revLookup[b64.charCodeAt(i)] << 2) |
(revLookup[b64.charCodeAt(i + 1)] >> 4)
arr[curByte++] = tmp & 0xFF
}
if (placeHoldersLen === 1) {
tmp =
(revLookup[b64.charCodeAt(i)] << 10) |
(revLookup[b64.charCodeAt(i + 1)] << 4) |
(revLookup[b64.charCodeAt(i + 2)] >> 2)
arr[curByte++] = (tmp >> 8) & 0xFF
arr[curByte++] = tmp & 0xFF
}
return arr
}
function tripletToBase64 (num) {
return lookup[num >> 18 & 0x3F] +
lookup[num >> 12 & 0x3F] +
lookup[num >> 6 & 0x3F] +
lookup[num & 0x3F]
}
function encodeChunk (uint8, start, end) {
var tmp
var output = []
for (var i = start; i < end; i += 3) {
tmp =
((uint8[i] << 16) & 0xFF0000) +
((uint8[i + 1] << 8) & 0xFF00) +
(uint8[i + 2] & 0xFF)
output.push(tripletToBase64(tmp))
}
return output.join('')
}
function fromByteArray