diff --git a/CHANGES.md b/CHANGES.md new file mode 100644 index 0000000..0eacc60 --- /dev/null +++ b/CHANGES.md @@ -0,0 +1,3 @@ +## 2017-11-13 Release 0.1.0 + +Initial release. diff --git a/LICENSE b/LICENSE index d179904..e49d64d 100644 --- a/LICENSE +++ b/LICENSE @@ -1,6 +1,6 @@ MIT License -Copyright (c) 2017 C2FO Lab +Copyright (c) 2017 C2FO Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/README.md b/README.md index 4454820..4849b5a 100644 --- a/README.md +++ b/README.md @@ -1,2 +1,740 @@ -# IPFSecret -Symmetric cryptography wrapper for IPFS files with web gateway support +[![npm](https://img.shields.io/npm/v/ipfsecret.svg)]() [![license](https://img.shields.io/github/license/c2fo-lab/ipfsecret.svg)]() [![npm](https://img.shields.io/npm/dw/ipfsecret.svg)]() [![node](https://img.shields.io/node/v/ipfsecret.svg)]() [![GitHub last commit](https://img.shields.io/github/last-commit/c2fo-lab/ipfsecret.svg)]() + + * [Introduction](#introduction) + * [Install](#install) + * [Quickstart](#quickstart) + * [Warnings](#warnings) + * [Testing](#testing) + * [API](#api) + * [Command-line web gateways](#command-line-web-gateways) + * [Implementation](#implementation) + * [Passphrase file](#passphrase-file) + * [Security](#security) + * [Troubleshooting](#troubleshooting) + * [Acknowledgements](#acknowledgements) + * [Todo](#todo) + * [See also](#see-also) + +

+ +

+ +# Introduction + +IPFSecret lets you encrypt and decrypt IPFS files with a secret passphrase. + +If you are new to IPFS, there are guides for [getting started](https://ipfs.io/docs/getting-started/) and [running the daemon with the right port](https://github.com/ipfs/js-ipfs-api#running-the-daemon-with-the-right-port). + +# Install + + λ npm install -g ipfsecret + +# Quickstart + +## Add a file + + λ ipfsecret add README.md + Passphrase? + Confirm passphrase: + QmeVMn7oLoSC7ShLeLPu2tMrGq4TEr9icSxPbKxAF7CJ7Q + +## Get a file + + λ ipfsecret get QmeVMn7oLoSC7ShLeLPu2tMrGq4TEr9icSxPbKxAF7CJ7Q + Passphrase? + λ head -n1 ipfsecret-decrypted-QmeVMn7oLoSC7ShLeLPu2tMrGq4TEr9icSxPbKxAF7CJ7Q + * [Introduction](#introduction) + λ + +## Add a directory + + λ ipfsecret add -r node_modules/webcrypto-crypt + Passphrase? + Confirm passphrase: + QmfSi8rg7ismstGwDKoEwKySCr8Ptt7XHV1xMkB27DAARv + +## Get a directory + + λ ipfsecret get QmfSi8rg7ismstGwDKoEwKySCr8Ptt7XHV1xMkB27DAARv + Passphrase? + λ ls ipfsecret-decrypted-QmfSi8rg7ismstGwDKoEwKySCr8Ptt7XHV1xMkB27DAARv/node_modules/webcrypto-crypt/ + CHANGES.md README.md bin examples lib test + LICENSE SIGNED.txt dist index.js package.json + +## Add a file, include web interface + + λ ipfsecret add -w README.md + Passphrase? + Confirm passphrase: + http://127.0.0.1:8080/ipfs/QmNndRMk9sQzYGmszosGCYUiDm9WBKGy512bLZNoxcAcPm/ipfsecret.html + +## Add a directory, include web interface + + λ ipfsecret add -wr node_modules/webcrypto-crypt + Passphrase? + Confirm passphrase: + http://localhost:8080/ipfs/QmWCGgmQdT1xNd44kUwEqY61aX551kRMwrXdvBPBGA1Qto/ipfsecret.html + +# Warnings + +* File contents added via IPFSecret are encrypted but file and directory names are stored in clear text. +* There are [problems with symmetric algorithms](http://web.archive.org/web/20150916184759/http://www.informit.com/articles/article.aspx?p=102212). +* Depending on [pinning](https://discuss.ipfs.io/t/replication-on-ipfs-or-the-backing-up-content-model/372/2) activity, your encrypted data could be distributed to many nodes across the IPFS network. +* Entities with access to your IPFSecret multihashes that then guess, learn, or crack the relevant passphrase will be able to decrypt your data. +* Unknown bugs in this code or its dependency tree (e.g., the [webcrypto-crypt](https://c2fo-lab.github.io/webcrypto-crypt) package) could render encryption ineffective. +* Downloading large files over IPFS web gateways can be slow and in the case of decryption there is currently no feedback on download progress. +* [Private Networks](https://github.com/ipfs/go-ipfs/blob/master/docs/experimental-features.md#private-networks), [public-key cryptography](https://en.wikipedia.org/wiki/Public-key_cryptography) tools, or something like [Decentralized Could](https://decentralized.cloud/) or [Firefox Send](https://send.firefox.com/) may better fit your needs. + +# Testing + +## Node.js + +Optionally run the relevant daemon using the [```--offline```](https://github.com/ipfs/go-ipfs/pull/2696#issuecomment-242664950) option for the duration of the tests. Tests assume the API settings present in [```lib/config.js```](https://github.com/c2fo-lab/ipfsecret/blob/master/lib/config.json#L56-L60). + + λ npm run test + +## Web browsers + +As part of the install process, IPFSecret adds a multihash for browser testing and extracts it to ```.examples/```. The password will be ```justtesting``` and you can access it over the local web gateway using the same multihash. + +## Tested environments + +| **OS** | **Environment** | **Version** | +| :-------- | :------- | :------- | +| Mac Sierra | Chrome | 62 | +| Mac Sierra | Firefox | 57 | +| Mac Sierra | Node | 8.9.1 | +| Mac Sierra | Safari | 11.0 | + +### Help + +#### Commands + + λ ipfsecret --help + Usage: ipfsecret [options] + + Commands: + get Retrieve & decrypt encrypted files from IPFS + add Encrypt & add files to IPFS + list List known HTTPS gateways + + Options: + --debug, -d Print debugging info to stderr [boolean] [default: false] + --api, -a Specify IPFS API configuration [string] [default: "/ip4/127.0.0.1/tcp/5001"] + --gateway, -g Use this HTTP(S) gateway when returning gateway address [string] [default: false] + --version, -v Display version and exit [boolean] [default: false] + --help Show help [boolean] + +##### add + + λ ipfsecret add -h + File or directory required + Usage: ipfsecret add [options] [file|dir] + + Options: + --debug, -d Print debugging info to stderr [boolean] [default: false] + --api, -a Specify IPFS API configuration [string] [default: "/ip4/127.0.0.1/tcp/5001"] + --gateway, -g Use this HTTP(S) gateway when returning gateway address [string] [default: false] + --version, -v Display version and exit [boolean] [default: false] + --help Show help [boolean] + --web, -w Add web interface [boolean] [default: "false"] + --naked, -n With --web, return naked hash vs URL [boolean] [default: "false"] + --recursive, -r Add as directory, recursively [boolean] [default: "false"] + --hidden, -H When adding directory, include hidden files [boolean] [default: "false"] + +##### get + + λ ipfsecret get --help + Multihash required + Usage: ipfsecret get [multihash] + + Options: + --debug, -d Print debugging info to stderr [boolean] [default: false] + --api, -a Specify IPFS API configuration [string] [default: "/ip4/127.0.0.1/tcp/5001"] + --gateway, -g Use this HTTP(S) gateway when returning gateway address [string] [default: false] + --version, -v Display version and exit [boolean] [default: false] + --help Show help [boolean] + --output, -o Path where output should be stored [string] + +#### example of specifying output paths + + λ ipfsecret get -o decrypted.md QmXCsAFuP7Jv2bePvcZEmHeygSHLYfVEB9rtkvhaKF5pL9 + Passphrase? + λ head -n1 decrypted.md + * [Purpose](#purpose) + + λ ipfsecret get -o decrypted-dir-test QmfSi8rg7ismstGwDKoEwKySCr8Ptt7XHV1xMkB27DAARv + Passphrase? + λ ls decrypted-dir-test/node_modules/webcrypto-crypt/ + CHANGES.md README.md bin examples lib test + LICENSE SIGNED.txt dist index.js package.json + +# API + +Please assume the following lines precede these examples: + +```javascript +const IPFSecret = require('ipfsecret'), + ipfsecret = new IPFSecret(); +``` + +## ipfsecret.add(path, passphrase) + +Wraps [ipfs.files.add](https://github.com/ipfs/interface-ipfs-core/tree/master/API/files) to require a ```path``` to add to IPFS and a ```passphrase``` for encryption. Encrypts each file found along the path using [webcrypto-crypt](https://c2fo-lab.github.io/webcrypto-crypt) and appends the ```.wcrypt``` suffix before adding. + +### Add file + +```javascript +ipfsecret.add('./README.md', 'justtesting') + .then(results => { + console.log(results); + }) + .catch(err => { + console.error(err); + }); +``` + +Example: + + [ { path: 'README.md.wcrypt', + hash: 'QmcrMFv4f4yef5EpdM9mUTGiE4msi2VKLmTPbGenRaiKLd', + size: 20871 } ] + +### Add directory + +```javascript +ipfsecret.add('./test', 'justtesting') + .then(results => { + console.log(results); + }) + .catch(err => { + console.error(err); + }); +``` + +Example: + + [ { path: 'ipfsecret/test/add-indexed.js.wcrypt', + hash: 'QmPm5MGHooEiDuiJjDg5dFRvaNgyTNYuM7Lx4gqj5k77cB', + size: 8013 }, + { path: 'ipfsecret/test/add.js.wcrypt', + hash: 'Qmcdj2aRshwSkVnEUSAANcHEmbyjb1tnt9Cg5Ubh2bxvav', + size: 6900 }, + { path: 'ipfsecret/test/get.js.wcrypt', + hash: 'QmXYeFbCBL8vgYKsvy4K98kYNvqDHMXVeEogR6zQzdedg7', + size: 5322 }... + +0 byte files are skipped during encryption. Symbolic links encountered are resolved and encrypted as separate files. + +### Other options + +If the caller passes in an Object instead of ```passphrase```, ```ipfsecret.add``` recognizes the following key:value pairs: + +```javascript + const options = { + directory: 'mydirname', // Use this wrapping dir, default 'ipfsecret' + hidden: false, // Include hidden files. Default true + passphrase: 'justtesting', // Use value to encrypt, always required + root: true, // Return just multihash. Default false + suffix: 'myfilesuffix', // Use this suffix, default 'wcrypt' + wcrypt: {config:{crypto:tagLength:112}} // Pass options to webcrypto-crypt (see below) + }; +``` + +#### Root multihash only + +The multihash is returned as a [Buffer](https://nodejs.org/api/buffer.html): + +```javascript +const bs58 = require('bs58'); + +ipfsecret.add('./test', {passphrase:'justtesting', root:true}) + .then(hash => { + console.log(bs58.encode(hash)); + }) + .catch(err => { + console.error(err); + }); +``` + +Example: + + Qmf22oxRTsz6CPWf2xDZeF729xdBx7ULDQsdtqpXYh8UKV + +#### Custom file suffix + +```javascript +ipfsecret.add('./test', {passphrase:'justtesting', suffix: 'shazam'}) + .then(results => { + console.log(results); + }) + .catch(err => { + console.error(err); + }); +``` + +Example: + + [ { path: 'ipfsecret/test/add-indexed.js.shazam', + hash: 'QmY4EWxfvBVAUVzpbB7wXhktWLFwE4xunx1jiFbpiNWiKM', + size: 8013 }, + { path: 'ipfsecret/test/add.js.shazam', + hash: 'QmRGKq3VHsuX4kyerYE1atNBC7wCu2gRpmxXqocKdXTQsT', + size: 6900 }, + { path: 'ipfsecret/test/get.js.shazam', + hash: 'QmRU2qKJBScmedhcDgGGPCvtpWVnasQEJdkF9UvVEM9L7N', + size: 5322 },... + +#### Custom wrapping dir + +```javascript +ipfsecret.add('./test', {passphrase:'justtesting', directory:'shazam'}) + .then(results => { + console.log(results); + }) + .catch(err => { + console.error(err); + }); +``` + +Example: + + [ { path: 'shazam/test/add-indexed.js.wcrypt', + hash: 'QmTWSp9uyPG2DuxFuw3XBhuqJd7cq4zemz4iJqxMw6693r', + size: 8013 }, + { path: 'shazam/test/add.js.wcrypt', + hash: 'QmXC348Z6PZGUCSz4tMGaRuhcQ7cgiAxhD8h4gbqhCoAEn', + size: 6900 }, + { path: 'shazam/test/get.js.wcrypt', + hash: 'QmcU8eu2fWFfUsM1SkKq8zSrmDa9hWB6hze6yVzNtDKE2G', + size: 5322 }... + +#### Custom cryptography settings + +To pass custom settings to [webcrypto-crypt](https://c2fo-lab.github.io/webcrypto-crypt), use the ```wcrypt``` options attribute: + +```javascript +ipfsecret.add('./test', { + passphrase:'justtesting', + root: true, + wcrypt: { + config: { + crypto: { + tagLength: 112 + }, + derive: { + hash: 'SHA-256', + length: 192, + iterations: 5000 + }, + paranoid: true + } + } +}) + .then(hash => { + console.log(hash); + }) + .catch(err => { + console.error(err); + }); +``` + + QmesGPZmiAgGhQSvEF7m7AdotmMygaPsJHvUH9STRjttwB + λ head -n1 QmesGPZmiAgGhQSvEF7m7AdotmMygaPsJHvUH9STRjttwB/test/add-index.js.wcrypt + WCRYPT00.01.125000112192SHA-256.... + +## ipfsecret.get(hash, passphrase) + +Wraps [ipfs.files.get](https://github.com/ipfs/interface-ipfs-core/tree/master/API/files) to require a multihash for retrieval and a ```passphrase``` for decryption. If ```passphrase``` is accepted, returns a promise that resolves to an object stream of decrypted file objects. + +Any files encountered during an ```ipfsecret.get``` operation that could not be decrypted will not be retrieved. + +Consider the following IPFS directory, encrypted with the passphrase, "学年別漢字配当表": + + λ ipfs ls QmZdNHJpzvTYqS3ba6EW4tryGaaEjHYyqY4ji6jZGK6Les/assets/fonts + QmX6KnVkx6L3uXsLcTfi5d8SUwc4F1DLTEMeYgeRWYscoc 34016 roboto-v16-latin-300.woff.wcrypt + QmYWKumL3aj54gRyG11dLRKp9eon9kCZzDM4MDMdzg7nQg 26475 roboto-v16-latin-300.woff2.wcrypt + QmXAVPjgS2FiCpGXz7pA5Prh5WjHJtan1H1L7PSNNZLMCz 37008 roboto-v16-latin-300italic.woff.wcrypt + QmaX7JAakBrgw5GAaMSuqxGyyntQsmxHc3jHLDDuuMsxSt 29439 roboto-v16-latin-300italic.woff2.wcrypt + QmPPoCqdCCxNEqyPJmsEqasDUes9uP49UAzyJ6S4JVEnJb 34001 roboto-v16-latin-700.woff.wcrypt + QmeFr49dWjcRJm9LM6vzfVEHZaZB8JwbgA5fXkq68vL4gn 26494 roboto-v16-latin-700.woff2.wcrypt + QmSsuY2teXgFRk5dXx4P2CBe4VG4QmmjJsAXVMRofpKmvP 35974 roboto-v16-latin-700italic.woff.wcrypt + Qmb3LegLP2kNLmvjUPsWkt82mVPX9BVGCbgTajj5KidrRG 28344 roboto-v16-latin-700italic.woff2.wcrypt + QmU5ehUCXbbMcoEDHgdp55T51kqi1X1Qjh3VeeZAz94xdN 33648 roboto-v16-latin-regular.woff.wcrypt + QmUWp3DJNujDFXvQaxdR8qm3ueYnGd6tnnsHuVP4qmiQVL 26516 roboto-v16-latin-regular.woff2.wcrypt + λ + +```javascript +const fs = require('fs'), + path = require('path'), + hash = 'QmZdNHJpzvTYqS3ba6EW4tryGaaEjHYyqY4ji6jZGK6Les'; + +ipfsecret.get(hash, '学年別漢字配当表') + .then((stream) => {stream.on('data', (obj) => { + if (obj.content) { + var filename = path.basename(obj.path), + writeable = fs.createWriteStream(filename); + obj.content.pipe(writeable); + obj.content.on('finish', () => { + console.log('Wrote ' + filename); + }); + obj.content.on('error', (err) => { + console.error('Error: ' + err); + }); + } + });}) + .catch(err => { + console.error(err); + }); +``` + +Example: + + Wrote roboto-v16-latin-300.woff + Wrote roboto-v16-latin-300.woff2 + Wrote roboto-v16-latin-300italic.woff + Wrote roboto-v16-latin-300italic.woff2 + Wrote roboto-v16-latin-700.woff + Wrote roboto-v16-latin-700.woff2 + Wrote roboto-v16-latin-700italic.woff + Wrote roboto-v16-latin-700italic.woff2 + Wrote roboto-v16-latin-regular.woff + Wrote roboto-v16-latin-regular.woff2 + λ ls roboto-v16-latin-* + roboto-v16-latin-300.woff roboto-v16-latin-300italic.woff roboto-v16-latin-700.woff roboto-v16-latin-700italic.woff roboto-v16-latin-regular.woff + roboto-v16-latin-300.woff2 roboto-v16-latin-300italic.woff2 roboto-v16-latin-700.woff2 roboto-v16-latin-700italic.woff2 roboto-v16-latin-regular.woff2 + λ file roboto-v16-latin-300.woff + roboto-v16-latin-300.woff: Web Open Font Format, flavor 65536, length 18972, version 1.1 + +### Other options + +If the caller passes in an Object instead of a passphrase, ```ipfsecret.get``` recognizes the following key:value pairs: + +```javascript +const options = { + passphrase: 'justtesting', // Use value to encrypt data, always required + wcrypt: {config:{crypto:tagLength:112}} // Pass options to cryptography package +}; +``` + +## ipfsecret.addIndexed(path, passphrase) + +Otherwise identical to ```ipfsecret.add```, ```ipfsecret.addIndexed``` adds HTML, JavaScript, CSS, and fonts that together provide a browser interface for listing and decrypting ipfsecret-encrypted files. This is an alias for ```ipfsecret.add(path, {passphrase: p, indexed: true}```. + +### Add directory and include browser interface files + +```javascript +ipfsecret.addIndexed('./test', 'justtesting') + .then(results => { + console.log(results); + }) + .catch(err => { + console.error(err); + }); +``` + +Example: + + [ { path: 'ipfsecret/ipfsecret/styles/normalize.css', + hash: 'QmbfTL2ZsgZzhH5Cz6pcnChUkrDsozHnjnqSfYAbCex7W2', + size: 7730 }, + { path: 'ipfsecret/ipfsecret/styles/fonts.css', + hash: 'Qmc8XfJ4w1LjV6uK4q2ENzREdTELLpnGWdoKfnjkXHH1Vm', + size: 1992 }, + { path: 'ipfsecret/ipfsecret/styles/milligram.css', + hash: 'QmaFP6KqC1LrkBadFcxgqSKnxqhjByiALpjSeAoYtzMDth', + size: 8729 }, + { path: 'ipfsecret/ipfsecret/js/ipfsecret.js', + hash: 'QmTWa8Hx5G5M72xb3A3bbdmkvvpSM8UZ5ct8oqLZSgRfYn', + size: 76326 }, + { path: 'ipfsecret/ipfsecret/fonts/roboto-v16-latin-300.woff', + hash: 'QmVeWJjZaoXLitapfpDHVWxm7BwqqiT6FfeVdDHxMCkCXn', + size: 18986 }, + { path: 'ipfsecret/ipfsecret/fonts/roboto-v16-latin-300.woff2', + hash: 'QmNuucbg8ojSkDvN2x4HJBjiLqN9vdcKz5VPee6RroASgX', + size: 14707 }, + ... + +### Other options + +#### Content overrides + +In addition to all the options supported by ```ipfsecret.add```, you may override ```ipfsecret.addIndexed```'s CSS, font directory, and JavaScript build by passing in overriding options: + +```javascript +ipfsecret.addIndexed('./test', { + baseCss: './myBase.css', + dialogCss: './myDialog.css', + fontCss: './myFonts.css', + mainCss: './myStyles.css', + mapCss: './myStyles.css.map', + fontsDir: './myFontsDirectory', + jsPath: './myJavaScriptBuild.js', + passphrase: 'justtesting', +}) + .then(results => { + console.log(results); + }) + .catch(err => { + console.error(err); + }); +``` + +## ipfsecret.getGatewayList() + +Return an array of currently known HTTP/S gateways; used by the command-line utility. + +```javascript +console.log(ipfsecret.getGatewayList()); +``` + + [ 'https://gateway.ipfs.io', + 'https://earth.i.ipfs.io', + 'https://mercury.i.ipfs.io', + 'https://gateway.ipfsstore.it:8443', + 'https://scrappy.i.ipfs.io', + 'https://chappy.i.ipfs.io' ] + +## IPFSecret.DEBUG = true | false + +If set to ```true```, send debugging statements to stderr. Default ```false```. + +## IPFSecret.version + +Returns the current version of this library, e.g., ```0.1.2```. + +## Custom API endpoint + +When instantiating a new IPFSecret object, you may optionally pass in ```options``` to override the default IPFS connection parameters: + +```javascript + const ipfsecret = new IPFSecret({ + host: '192.168.1.233', // default 'localhost' + port: 5002, // default 5001 + proto: 'http' // default 'http' + }); +``` + +# Command-line web gateways + +## List known web gateways + + λ ipfsecret list + 0 - https://gateway.ipfs.io + 1 - https://earth.i.ipfs.io + 2 - https://mercury.i.ipfs.io + 3 - https://gateway.ipfsstore.it:8443 + 4 - https://scrappy.i.ipfs.io + 5 - https://chappy.i.ipfs.io + +## Specify a web gateway (instead of localhost) when outputting result + + λ ipfsecret add -g3 -wr node_modules/webcrypto-crypt/ + Passphrase? + Confirm passphrase: + https://gateway.ipfsstore.it:8443/ipfs/QmWqwUpf4jBdTb8BRxaLUvPQj3JMUtMQe1Kxo2sm3noHE7/ipfsecret.html + +## Specify a custom gateway when outputting hash + + λ ipfsecret add -g "https://mygateway.io:8088" -wr node_modules/webcrypto-crypt/ + Passphrase? + Confirm passphrase: + https://mygateway.io:8088/ipfs/QmYYoHfaAcvkRQy6bubTChkXPi2c9d1r6vBatWeRXMr7p5/ipfsecret.htmlλ + +# Implementation + +## Cryptography + +IPFSecret's encryption depends on WebCrypto's [SubtleCrypto](https://www.w3.org/TR/WebCryptoAPI/#subtlecrypto-interface) interface, specifically the algorithms [PBKDF2](https://www.w3.org/TR/WebCryptoAPI/#pbkdf2) and [AES-GCM](https://www.w3.org/TR/WebCryptoAPI/#aes-gcm). It then marshals the encrypted chunks into IPFS objects and adds these to IPFS as new files. Decryption is carried out via the same SubtleCrypto interface, with the caller supplying the correct passphrase along with the relevant multihash to decrypt the files as they are retrieved. See [webcrypto-crypt](https://c2fo-lab.github.io/webcrypto-crypt) for more information. + +Decrypting IPFS files in the web browser is currently supported but encrypting in the browser is not supported. + +## Web browsers + +### HTML page + +

+ +

+ +By default, IPFSecret publishes the index using the filename ```ipfsecret.html```. This can be overridden to specify any filename but be aware ```index.html``` [has special meaning](https://github.com/ipfs/ipfs/issues/167#issuecomment-329969289) for IPFS gateways. + +### Markup and styling + +When calling ```addIndexed()``` from JavaScript or specifying the ```--web``` argument to the ```ipfsecret``` command-line utility, IPFSecret will generate unencrypted HTML pages that contain a directory listing and buttons to decrypt any file by providing the passphrase. The HTML is currently styled using [Milligram](http://milligram.io/) but as noted in the [Content overrides](#content-overrides) section, you may also specify your own CSS and accompanying fonts. + +### Decryption + +IPFSecret currently accesses encrypted IPFS files from the web browser as [Blobs](https://developer.mozilla.org/en-US/docs/Web/API/Blob) and decrypts them via [webcrypto-crypt](https://c2fo-lab.github.io/webcrypto-crypt). + +### Decrypted file size limits + +[Filesaver.js documentation](https://github.com/eligrey/FileSaver.js/#supported-browsers) shows the download size limits of the various browsers. If IPFSecret detects that an encrypted file is larger than the current browser's limit, instead of decrypting it will display a message suggesting other options. Encrypted files can always be downloaded from the gateway and later decrypted using Node.js or the command-line. + +### Encrypted file modified times + +The ```Date modified``` field populated in the web interface reflects the modified time of the original, unencrypted file, versus the time that the encrypted version was created. + +### Long download times & decryption times + +IPFSecret currently relies on the browser's [Fetch API](https://developer.mozilla.org/en-US/docs/Web/API/Fetch_API) to access files as blobs, and there is currently no support in the API for showing download progress. In the case of accessing large files over slow IPFS web gateways, you may end up waiting a good while for the encrypted file to download before decryption can begin, without knowing how much longer the download will take to complete. Decryption in the browser can also be slow, particularly with blobs approaching 500MB or more. There is currently a [Todo](#todo) item to migrate these operations to the [Streams API](https://developer.mozilla.org/en-US/docs/Web/API/Streams_API) which may improve performance in future releases. + +### Offline mode + +IPFSecret web pages try to detect whether or not the current browser is connected to the internet and, if not connected, attempt to redirect to the local IPFS HTTP gateway. Decryption should work in the browser whether or not the user is connected to the internet, provided the multihashes in question are locally accessible. + +# Passphrase file + +See [.wcryptpass](https://c2fo-lab.github.io/webcrypto-crypt#wcryptpass) + +# Security + +Security Mail: labs@c2fo.com
+PGP key fingerprint: [````E838 B51C C63F 7ED6 0980 9535 4D46 5218 A674 6F81````](https://pgp.mit.edu/pks/lookup?search=0xE838B51CC63F7ED6098095354D465218A6746F81)
+Keyserver: [pgp.mit.edu](https://pgp.mit.edu)
+ +# Troubleshooting + +IPFSecret is not fast. For large directories and files, you may just need to wait it out... + + λ osxinfo + User : alfonz + Time: : Sun Nov 12 13:54:49 2017 + Model : MacBookPro10,1 + Processor : Intel(R) Core(TM) i7-3615QM CPU @ 2.30GHz + OS : Darwin + Release : 16.7.0 + Disk : 80.10% of 249.78 GB + Memory : 10254 MB of 17180 MB + Shell : /bin/bash + Terminal : screen + Memory : 10254 MB of 17180 MB + Graphics : Intel HD Graphics 4000 @ 1536 MB + Graphics : NVIDIA GeForce GT 650M @ 1024 MB + Packages : no packages found + Uptime : 1 day 04:37 + + λ ipfs --version + ipfs version 0.4.11 + + λ ipfs init + ... + + λ ipfs daemon --offline & + [1] 12178 + λ Initializing daemon... + Swarm not listening, running in offline mode. + API server listening on /ip4/127.0.0.1/tcp/5001 + Gateway (readonly) server listening on /ip4/127.0.0.1/tcp/8080 + Daemon is ready + + λ git log | head -n4 && du -sh + commit bebc6082da0a9f5d47a1ea2edc099bf671058bd4 + Author: Linus Torvalds + Date: Sun Nov 12 10:46:13 2017 -0800 + + 2.9G . + + λ time ipfsecret add -wrH . + Passphrase? + Confirm passphrase: + http://127.0.0.1:8080/ipfs/QmdScWuXY97CDsqUpxCgF6RjtYnu8qzf66EaWpTdZNfvdN/ipfsecret.html + real 4m32.701s + user 3m53.192s + sys 0m20.093s + λ + + λ cd .. + λ time ipfsecret -o decrypted-linux get QmdScWuXY97CDsqUpxCgF6RjtYnu8qzf66EaWpTdZNfvdN + Passphrase? + + real 3m27.587s + user 7m20.771s + sys 0m29.577s + + λ du -sh decrypted-linux + 2.9G decrypted-linux + + λ diff -Nur ./decrypted-linux ./linux + λ # but some 0 byte files and empty dirs will cause differences (diff -r) + + λ ls -lh ubuntu.vdi + -rw------- 1 alfonz staff 2.7G Jul 27 19:06 ubuntu.vdi + + λ time ipfsecret add ubuntu.vdi + Passphrase? + Confirm passphrase: + Qmd4tq3Q7PVzNcfDojdx7koRsEfVMnitvAFSR4EDhirUUj + real 0m47.569s + user 0m27.784s + sys 0m6.920s + + λ time ipfsecret get -o ubuntu.vdi.decrypted Qmd4tq3Q7PVzNcfDojdx7koRsEfVMnitvAFSR4EDhirUUj + Passphrase? + + real 2m10.282s + user 2m4.236s + sys 0m10.424s + + λ diff ubuntu.vdi.decrypted ubuntu.vdi + λ + +## Timeouts + +You may encounter timeouts after connecting to the API server. In these cases you can try adding the content again: + + λ ipfsecret add -wr linux/ + Passphrase? + Confirm passphrase: + { Error: connect ETIMEDOUT 127.0.0.1:5001 + at Object._errnoException (util.js:1041:11) + at _exceptionWithHostPort (util.js:1064:20) + at TCPConnectWrap.afterConnect [as oncomplete] (net.js:1153:14) + code: 'ETIMEDOUT', + errno: 'ETIMEDOUT', + syscall: 'connect', + address: '127.0.0.1', + port: 5001 } + λ ipfsecret add -wr linux/ + Passphrase? + Confirm passphrase: + http://localhost:8080/ipfs/Qma7w6RchCgv7E8yqeqeU9viPE97RGMuih8yvE2NL4555q/ipfsecret.htmlλ + +## File signature warnings + +When decrypting directories that contain the web user interface, the unencrypted web interface files may trigger this warning: + + Error: Error: Invalid file signature webcrypto-crypt0.1.15 + +## Invalid index entries + +Directories that contained no files or contained only 0-byte files will currently result in invalid links in the HTML indices. + +## Out of memory + +If you hand ```ipfsecret add``` a very large directory, you may encounter a fatal error like: + + FATAL ERROR: CALL_AND_RETRY_LAST Allocation failed - JavaScript heap out of memory + +In these cases you might consider writing several directories as separate operations. + +# Acknowledgements + +* Decryption via WebCrypto in the browser uses a modified version of the [binary-split](https://github.com/maxogden/binary-split) function. +* Modal box implementation from [modalbox](https://github.com/CristianDeveloper/modalbox). + +# Todo + +* Add automated tests for browser-based decryption. +* Fix UI navigation when user specifies ```.``` or ```../../../```, etc . +* Start ```ipfs --daemon``` if it's not already running for duration of tests. +* Support embed and decrypt Base64 and hexadecimal encoded data in HTML files. +* Support streaming decryption through the forthcoming [Streams API](https://developer.mozilla.org/en-US/docs/Web/API/Streams_API). +* Rewrite install.sh in node for portability +* Test on Win and Linux. +* Support [progress bar on the command line](https://github.com/ipfs/js-ipfs/pull/1036). + +# See also + +* [IPFS](https://ipfs.io/) +* [webcrypto-crypt](https://c2fo-lab.github.io/webcrypto-crypt) diff --git a/SIGNED.txt b/SIGNED.txt new file mode 100644 index 0000000..f39d9c8 --- /dev/null +++ b/SIGNED.txt @@ -0,0 +1,46 @@ +-----BEGIN PGP SIGNED MESSAGE----- +Hash: SHA512 + +assets/css/dialog.css,4.0K,821334ef1c259e0b2539aa9714873f7dee017b91a8e14c98d29fd7b3976af8e5 +assets/css/fonts.css,4.0K,312db64124154f579839d22282c4b0a51aa7d76ff98f872c80aa91633ec07805 +assets/js/ipfsecret-decrypt.js,12K,2ee2604b4421962246296865716b67e56e9466404001ad113548f0723491f466 +bin/browserify.js,4.0K,9495034fc074de5349f143d1d83e281db37aa7248a46cda77df92aa4f04d37ce +bin/get-fonts.js,4.0K,8f72986813ad44102ef243d6e32d81306bbc17ef96c7d6c40757b001a2076b70 +bin/install.sh,4.0K,19381a15ade1693b201dcd94862d909c6744ffb61f16299204e4892c22174b84 +bin/ipfsecret.js,16K,314fed67f48ce583dd416f3d8c7ed6ca2d4d2dac8ab9dc7c4f62403cdebeb6c6 +CHANGES.md,4.0K,f59d6ddd25386d72f42c963926fdb29543ca3765ef4e70e8b5343a2401529699 +index.js,4.0K,afde30d82fbcd36601fae1364a9cb898ca01751c812047314f194f895264c5eb +lib/config.json,4.0K,3f08d9ae0f9469f6aa11b875af7f6187a7454a9b893ad2cf3c52fc2af4b6dc84 +lib/crypto/encrypt.js,8.0K,59e6f3b585e1d3e82b59fe9ed7fae641e1fb90a3de9f15bf103ac8ba4aa4db66 +lib/crypto/index.js,4.0K,eb8ca9af7eb250f8c63a9a72eae20af5b01a03a92e49718a58f827bf2b40ea8d +lib/indexer/html.js,12K,bd452f1ab2f901b311f19686bd34202cfca9b74f02bb8d22f49bf99c40ef13f0 +lib/indexer/index.js,8.0K,358a8f1a968ba04b4cbf3d56d532febd82f03445e8920191ffb684874d28c482 +lib/indexer/static/css.js,4.0K,9d941c5475d6117dffcba5161e03d0655fd1f76d6a6ebf67b2d0ea2e3ea88e26 +lib/indexer/static/fonts.js,4.0K,abc6825e203dc046ceb6d5c6cfe37c59affc37a573a683e4303d8aff952a9791 +lib/indexer/static/index.js,4.0K,1edb54ee440d7d5599670774a8960fd979ab9aa91a661630c8e41eaad3ab838f +lib/indexer/static/js.js,4.0K,040ce7e679921bbd34c45cc3a6ee8395cffeb480e2b1cef4619095889aa45f66 +lib/util/hashes.js,4.0K,bc69991c6ad7dc3df4b62174430e240a23bc33fdc4337fef7658ad27aecc53ca +lib/util/index.js,4.0K,e467f524bf11e541533d3e4b9080f8e368e17e4d916e97b9e2fe70718f964bcd +lib/util/options.js,4.0K,2cee630d705b258747a9bfeee33c446eae9a306e7ec1922f439e72eadd2d550f +lib/util/paths.js,4.0K,f3f07d47290e1fb20b24c1c583ba37df8d0dc39b7820a168a5e51ac559234895 +LICENSE,4.0K,a6f5c7d3a2606ed237064349fd7fe8fff0646f71512ef8e6842cd5e1923976c0 +package-lock.json,200K,108bd55d237d85497ba07dc469c191b3b08f2117b7111ebd8f4846f79d7d49a6 +package.json,4.0K,494cf44f1c6d6ee856a2950a4bc9f13ecf6fabbff2ccd8028cf4347ffb51cb32 +README.md,28K,b1e0b1c4d86b2cc5e56a2c16428dfde9116cf0facd93d1f874d663c4ff592863 +test/.wcryptpass,4.0K,a8f0fb0fd1a98f68b8442c9bd8b019a0e0ca81c579255bcf2c2bac76673733f9 +test/add-index.js,16K,b8d58c8c757778596d5834004c2cb9a57c82c89086f3b9d14a4c15b88870653d +test/add.js,8.0K,fc254bde104d358c4103d7e49a096b46d495f62773e3cb6431c06a732c5bc7e1 +test/get.js,8.0K,9db651c795b649d60cd62b73a4369a94ed28ef2c5cd43d39dd397875836a5de8 +test/misc.js,4.0K,bddab3f4415b26521eaf6200915ae26be1db978115f5ebfc4b7991aa27034175 +-----BEGIN PGP SIGNATURE----- +Version: Keybase OpenPGP v2.0.76 +Comment: https://keybase.io/crypto + +wsBcBAABCgAGBQJaCgCsAAoJEFXbw7aEigbJXloH/iCbTFa9HWgBeOR5DJUf55fs +kmdRl7889FodPuC9H9D+18G8Sp1Mfnobb9FBcCHicy1RCEV3FnhWNT8lvG8kGbcT +Z3+3KqJ+SBY6r9eSWDKlQMDLm4mKuKXVA3RkqMKgmssN1qF2jhBHXIKrTog2D8W5 +ktjNkNuLlpVz32o71zdaClkZCcMzuam9U1SMp7B49nk/MjvD0lj9tJEFo+ZR8JG9 +RUz57HPX4ojnYXoRrGr3h+SYatKi6GfmsmOd9BB8duyOn2sV1OiE5UWPrHN9bF2n +/sJTz1fQ2EkblmWkkPF86wLNcBmc2oawEqULHfLQNu8Gq6nwRzjpHIieQ/1+9Qs= +=gnOX +-----END PGP SIGNATURE----- diff --git a/assets/css/dialog.css b/assets/css/dialog.css new file mode 100644 index 0000000..d5df76e --- /dev/null +++ b/assets/css/dialog.css @@ -0,0 +1,55 @@ +/** + * Modal box Css + * @Version 1.0 + * @Author: Cristian Marian + * @E-mail: dev.cristian99@gmail.com + */ +.modal-sec-overlay { + display: none; + position: fixed; + z-index: 1; + left: 0; + top: 0; + width: 100%; + height: 100%; + overflow: auto; + background-color: rgba(0,0,0,0.1); +} +.modal-box { + background-color: #fefefe; + margin: 15% auto; + padding: 20px; +} +.modal-small {width: 375px;} +.close-btn { + background-color: #FFF; + color: #aaa; + float: right; + font-size: 15px; + font-weight: bold; + border: none; +} +.close-btn:hover, +.close-btn:focus { + outline: none; + color: black; + text-decoration: none; + cursor: pointer; +} +.modal-title { + font-size: 18px; + padding: 5px; + font-family: sans-serif; + border-bottom: 1px solid #CCC; +} +.modal-content { + padding: 5px; + font-size: 12px; + font-family: sans-serif; +} + +/* Modal Animation */ +@keyframes open-modal-animation{ + from { margin: -15% auto; } + to { margin: 15% auto; } +} diff --git a/assets/css/fonts.css b/assets/css/fonts.css new file mode 100644 index 0000000..53cc8bb --- /dev/null +++ b/assets/css/fonts.css @@ -0,0 +1,45 @@ +/* roboto-300 - latin */ +@font-face { + font-family: 'Roboto'; + font-style: normal; + font-weight: 300; + src: local('Roboto Light'), local('Roboto-Light'), + url('../fonts/roboto-v18-latin-300.woff2') format('woff2'), /* Chrome 26+, Opera 23+, Firefox 39+ */ + url('../fonts/roboto-v18-latin-300.woff') format('woff'); /* Chrome 6+, Firefox 3.6+, IE 9+, Safari 5.1+ */ +} +/* roboto-300italic - latin */ +@font-face { + font-family: 'Roboto'; + font-style: italic; + font-weight: 300; + src: local('Roboto Light Italic'), local('Roboto-LightItalic'), + url('../fonts/roboto-v18-latin-300italic.woff2') format('woff2'), /* Chrome 26+, Opera 23+, Firefox 39+ */ + url('../fonts/roboto-v18-latin-300italic.woff') format('woff'); /* Chrome 6+, Firefox 3.6+, IE 9+, Safari 5.1+ */ +} +/* roboto-regular - latin */ +@font-face { + font-family: 'Roboto'; + font-style: normal; + font-weight: 400; + src: local('Roboto'), local('Roboto-Regular'), + url('../fonts/roboto-v18-latin-regular.woff2') format('woff2'), /* Chrome 26+, Opera 23+, Firefox 39+ */ + url('../fonts/roboto-v18-latin-regular.woff') format('woff'); /* Chrome 6+, Firefox 3.6+, IE 9+, Safari 5.1+ */ +} +/* roboto-700 - latin */ +@font-face { + font-family: 'Roboto'; + font-style: normal; + font-weight: 700; + src: local('Roboto Bold'), local('Roboto-Bold'), + url('../fonts/roboto-v18-latin-700.woff2') format('woff2'), /* Chrome 26+, Opera 23+, Firefox 39+ */ + url('../fonts/roboto-v18-latin-700.woff') format('woff'); /* Chrome 6+, Firefox 3.6+, IE 9+, Safari 5.1+ */ +} +/* roboto-700italic - latin */ +@font-face { + font-family: 'Roboto'; + font-style: italic; + font-weight: 700; + src: local('Roboto Bold Italic'), local('Roboto-BoldItalic'), + url('../fonts/roboto-v18-latin-700italic.woff2') format('woff2'), /* Chrome 26+, Opera 23+, Firefox 39+ */ + url('../fonts/roboto-v18-latin-700italic.woff') format('woff'); /* Chrome 6+, Firefox 3.6+, IE 9+, Safari 5.1+ */ +} diff --git a/assets/js/ipfsecret-decrypt.js b/assets/js/ipfsecret-decrypt.js new file mode 100644 index 0000000..5f06dc5 --- /dev/null +++ b/assets/js/ipfsecret-decrypt.js @@ -0,0 +1,209 @@ +const BlobToBuffer = require('blob-to-buffer'), + { detect } = require('detect-browser'), + browser = detect(), + Config = require('../../lib/config.json'), + isOnline = require('is-online'), + toArrayBuffer = require('to-arraybuffer'), + FileSaver = require('file-saver'), + Path = require('path'), + Wcrypt = require('webcrypto-crypt'), + matcher = Buffer.from(Wcrypt.delimiter); + +document.addEventListener("DOMContentLoaded", function(event) { + + const blobSupport = { + firefox: {minVer: 20, maxSize: 800*1024*1024}, + chrome: {minvVer: 1, maxSize: 500*1024*1024}, + safari: {minVer: 10.1, maxSize: 100*1000*1024*1024}, + opera: {minVer: 15, maxSize: 500*1024*1024} + }; + + const byId = document.getElementById.bind(document), + close = byId('close-modal'), + content = byId('modal-box'), + duration = '0.5s', + open = byId('open-modal'), + p = (location.pathname).split('/'), + prefix = p.slice(0, p.length - 1).join('/') + '/', + hash = p[2], + opener = "open-modal-animation", + modal = byId('mymodal'); + + close.onclick = () => {modal.style.display = 'none';} + window.onclick = (e) => {if (e.target==modal) modal.style.display="none";}; + + function checkBlob(size) { + let broken = false; + switch (browser && browser.name) { + case 'chrome': + case 'firefox': + case 'opera': + case 'safari': + if ( + // unsupported browser version + (parseFloat(browser.version) + < + parseFloat(blobSupport[browser.name].minVer)) + || + // unsupported blob size for this browser + (size > parseInt(blobSupport[browser.name].maxSize)) + ) + { + broken = true; + alert(Config.ipfs.ui.browserDecryptNotSupported); + } + break; + default: + alert(browser.name + ' not supported'); + }; + return broken; + } + + function checkOnlineStatus() { + isOnline().then(online => { + if (!online && ((location.hostname !== 'localhost') && + (location.hostname !== '127.0.0.1'))) { + alert(Config.ipfs.ui.offlineMode); + location.href = `${ Config.ipfs.proto }://` + + `${ Config.ipfs.host }:${ Config.ipfs.gatewayPort }` + + `${ location.pathname }`; + } + }); + } + checkOnlineStatus(); + setInterval(checkOnlineStatus, parseInt(Config.ipfs.ui + .offlineMonitorInterval)); + + //stackoverflow.com/a/18650828 + function format(bytes, decimals) { + if(bytes === 0) return '0 B'; + if (!bytes) return ''; + const k = 1024, + dm = (decimals || 2) , + sizes = ['B','KB','MB','GB','TB','PB','EB','ZB','YB'], + i = Math.floor(Math.log(bytes) / Math.log(k)), + re = /^(\d+)\.(\d)$/, + val = parseFloat((bytes/Math.pow(k, i)).toFixed(dm)); + let text = val.toString(); + if (text.match(re)) text = text + '0'; + return text + ' ' + sizes[i]; + } + + function download() { + const filename = decodeURI(byId('filename').getAttribute('value')), + size = parseInt(byId('filesize').value), + done = format(size, 2), + f = Path.basename(filename).replace(/\.[^\.]+$/,''); + + let broken = checkBlob(size); + if (!broken) { + fetch(filename).then(function (res) { + byId('progress').innerHTML = Config.ipfs.ui.downloading + '...'; + res.blob() + .then(blob => {handleBlob(blob, size, done, f);}) + .catch(err => {alert(err);}); + }); + } + } + + function first(buf, offset) { + if (offset >= buf.length) return -1; + for (var i = offset; i < buf.length; i++) { + if (buf[i] === matcher[0]) { + let full = true; + for (var j = i, k = 0; j < i + matcher.length; j++, k++) { + if (buf[j] !== matcher[k]) { + full = false; + break; + } + } + if (full) return j - matcher.length; + } + } + let idx = i + matcher.length - 1; + return idx; + } + + function handleBlob(blob, size, done, f) { + let buffered, byteCount = 0, file, needHeader = true, wcrypt; + BlobToBuffer(blob, (err, buf) => { + if (err) console.error(err); + let last = 0, + offset = 0; + byId('form-fields').setAttribute('style', 'display:none') + while (true) { + let idx = first(buf, offset - matcher.length + 1); + if (idx !== -1 && idx < buf.length) { + if (needHeader) { + needHeader = false; + wcrypt = readHeader(buf, last, idx); + } + else { + wcrypt.rawDecrypt(buf.slice(last, idx)) + .then(data => { + setTimeout(() => { + byteCount = byteCount + data.length; + if (!file) file = Buffer.from(data); + else file = Buffer.concat([file, data]); + let percent = `${ ((byteCount / size) * 100).toFixed(2) }%`; + let complete = `(${ format(byteCount, 2) } of ${ done })`; + byId('progress').innerHTML = Config.ipfs.ui.decrypting + + ` ${ percent }
${ complete }`; + if (byteCount === size) { + const ab = toArrayBuffer(file); + const b = new Blob([new Uint8Array(ab)]); + FileSaver.saveAs(b, f); + modal.style.display = 'none'; + } + }, Config.ipfs.ui.decryptUpdateDelay); + }).catch((err) => {console.error(err);}); + } + offset = idx + matcher.length; + last = offset; + } + else { + buffered = buf.slice(last); + break; + } + } + }); + } + + function handleClicks(e) { + let target = e.target || e.srcElement; + if (target.getAttribute('value') == Config.ipfs.ui.decrypt) + showModal(target); + else if (target.getAttribute('value') == Config.ipfs.ui.download) + download(); + } + + function readHeader(buf, last, idx) { + try { + let passphrase = byId('passphrase').value; + byId('passphrase').value = null; + let data = Wcrypt.parseHeader(buf.slice(last, idx)); + data.material.passphrase = passphrase; + return new Wcrypt.cipher(data); + } + catch (err) {console.error(err);} + } + + function showModal(target) { + let filename = prefix + target.parentNode.parentNode + .querySelector('td:nth-child(1) > a').getAttribute('href'), + filesize = target.parentNode.parentNode + .querySelector('td:nth-child(2)').getAttribute('bytes'), + decrypted = decodeURI(Path.basename(filename) + .replace(/\.[^\.]+$/,'')); + byId('form-fields').setAttribute('style', 'display:block') + byId('progress').innerHTML = ''; + byId('modal-title').innerHTML = decrypted; + byId('filename').setAttribute('value', filename); + byId('filesize').setAttribute('value', filesize); + modal.style.display = 'block'; + content.style.animation = opener; + } + + document.body.addEventListener('click', handleClicks,false); + +}); diff --git a/bin/browserify.js b/bin/browserify.js new file mode 100755 index 0000000..0cba3c9 --- /dev/null +++ b/bin/browserify.js @@ -0,0 +1,65 @@ +#!/bin/sh +':' //; exec "$(command -v nodejs || command -v node)" "$0" "$@" + +var async = require('async'), + browserify = require('browserify'), + path = require('path'), + crypto = require('crypto'), + distJs = 'ipfsecret.js', + distFolder = './dist', + exampleFolder = './examples', + ipfsecretDir = 'assets/js', + ipfsecretSrc = 'assets/js' + path.sep + 'ipfsecret-decrypt.js', + wcryptSrc = require.resolve('webcrypto-crypt/index.js'), + fs = require('fs'), + mkdirp = require('mkdirp'); + +async.series([ + + function(callback) { + var folders = [distFolder, exampleFolder]; + folders.forEach(f => { + mkdirp(f, function (err) { + if (err) { + console.error('ERROR creating ' + f + + ': ' + err.message); + process.exit(0); + } + }); + }); + callback(); + }, + + function(callback) { + var b = browserify([wcryptSrc, ipfsecretSrc], + {standalone: 'IPFSecret'}).transform('babelify', + {presets: ['es2015']}); + b.ignore('node-webcrypto-ossl'); + var jsStream = b.bundle(); + var js = ''; + jsStream.on('data', function (buf) { + js += buf; + }); + jsStream.on('end', function () { + fs.writeFile(distFolder + path.sep + distJs, js, function(err) { + if(err) { + console.error('ERROR creating ' + distJs + ': ' + + err.message); + process.exit(0); + } + const hash = crypto.createHash('sha512'); + hash.update(js); + fs.writeFile(ipfsecretDir + path.sep + 'sha512.txt', + hash.digest('base64'), function(err) { + if(err) { + console.error('ERROR creating sha512.txt: ' + + err.message); + process.exit(0); + } + callback(); + }); + }); + }); + } + +]); diff --git a/bin/get-fonts.js b/bin/get-fonts.js new file mode 100755 index 0000000..660a592 --- /dev/null +++ b/bin/get-fonts.js @@ -0,0 +1,44 @@ +#!/bin/sh +':' //; exec "$(command -v nodejs || command -v node)" "$0" "$@" + +const AdmZip = require('adm-zip'), + Config = require('../lib/config.json'), + fs = require ('fs'), + path = require ('path'), + https = require ('https'), + { URL } = require('url'), + util = require('util'), + fsUnlink = util.promisify(fs.unlink), + options = new URL(Config.fonts.sourceUri); + +const indexFile = require.resolve('../.'), + pathParts = indexFile.split(path.sep), + mainFile = pathParts.pop(), + fontPath = pathParts.join(path.sep) + path.sep + 'assets' + path.sep + 'fonts'; + +var destination = fs.createWriteStream(Config.fonts.localFile); +destination.on('finish', () => { + console.log('Extracting files.'); + var zip = new AdmZip(Config.fonts.localFile); + zip.extractAllTo(fontPath, true); + fsUnlink(Config.fonts.localFile) + .then(() => { + console.log(Config.fonts.localFile + ' deleted.'); + }); +}); +destination.on('error', (err) => { + console.log(err.stack); +}); + +const req = https.request(options, (res) => { + res.on('data', (d) => { + destination.write(d); + }); + res.on('end', () => { + destination.end(); + }); +}); +req.on('error', (e) => { + console.error(e); +}); +req.end(); diff --git a/bin/install.sh b/bin/install.sh new file mode 100755 index 0000000..d19a2c1 --- /dev/null +++ b/bin/install.sh @@ -0,0 +1,12 @@ +#!/bin/sh + +chmod 0600 test/.wcryptpass +bin/get-fonts.js +bin/browserify.js +export WCRYPT_PASSFILE=test/.wcryptpass +MULTIHASH=`bin/ipfsecret.js add -wrn test` +cd ./examples +export WCRYPT_PASSFILE=../test/.wcryptpass +../bin/ipfsecret.js get "$MULTIHASH" +ipfs get "$MULTIHASH" +cd .. diff --git a/bin/ipfsecret.js b/bin/ipfsecret.js new file mode 100755 index 0000000..fce9564 --- /dev/null +++ b/bin/ipfsecret.js @@ -0,0 +1,389 @@ +#!/bin/sh +':' //; exec "$(command -v nodejs || command -v node)" "$0" "$@" +'use strict'; +const Config = require('../lib/config.json'), + bs58 = require('bs58'), + chop = require('chop'), + fs = require('fs'), + os = require('os'), + homePassFile = os.homedir() + '/.wcryptpass', + indexRegex = new RegExp(Config.ipfs.mainIndex + '$'), + mkdirp = require('mkdirp'), + passPath = process.env.WCRYPT_PASSFILE || homePassFile, + path = require('path'), + util = require('util'), + fsStat = util.promisify(fs.stat), + mkdir = util.promisify(mkdirp), + readline = require('readline-sync'), + readFile = util.promisify(fs.readFile), + subdirRegex = new RegExp('Qm.{44}' + Config.ipfs.mainSubdir), + yargs = require('yargs'), + IPFSecret = require('../.'), + prog = (path.basename(__filename).replace(/\.js$/,'')); + +if (!process.stdin.isTTY) { + console.error(`Piping data to ${ prog } not currently supported.`); + process.exit(0); +} +else { + var includeHidden = false; + const ipfsecret = getIPFSecretObject(); + const argv = getArgv(ipfsecret); + handleMainYargs(); + if (yargs.argv.version) { + process.stdout.write(IPFSecret.version + "\n"); + process.exit(0); + } + if (argv._.length < 1) { + yargs.showHelp(); + } + else { + const arg = argv._[1], command = argv._[0]; + validateCommand(arg, command); + exec(ipfsecret, arg, command); + } +} + +function add(ipfsecret, command, arg) { + fsStat(arg) + .then(stats => { + checkAddSanity(command, arg, stats); + encrypt(ipfsecret, arg); + }) + .catch(err => { + console.error(Config.err.noStat + err); + }); +} + +function addToIPFS(ipfsecret, arg, passphrase) { + return ipfsecret.add(arg, { + hidden: includeHidden, + indexed: yargs.argv.web, + passphrase: passphrase, + root: true + }) +} + +function checkAddSanity(command, arg, stats) { + if (stats.isDirectory() && !(yargs.argv.recursive)) { + console.error(`Error: '${ arg }' is a directory, use` + + ` '--recursive' to specify directories`); + process.exit(0); + } + else if (stats.isFile() && yargs.argv.recursive) { + console.error(`Error: '${ arg }' is a file, ` + + `'--recursive' only valid for directories`); + process.exit(0); + } + else if (yargs.argv.naked && yargs.argv.gateway) { + console.error(`Error: '--naked' is ` + + `invalid when used with '--gateway'`); + process.exit(0); + } +} + +function checkPassFile(stats) { + if (parseInt(stats.mode) === 33152) { + return readFile(passPath) + .then(data => { + const passphrase = chop.chomp(data.toString('utf8')); + if (!passphrase) throw new Error(Config.err.passReqd); + return passphrase; + }) + .catch(err => {handlePassErr(err);}); + } + else {throw new Error(Config.err.filePerms);} +} + +function debug(msg) { + var msg = Array.prototype.slice.call(arguments); + msg.unshift('[debug] '); + msg = msg.join(' '); + if (IPFSecret.DEBUG) console.error(msg); +} + +function decrypt(ipfsecret, arg, passphrase) { + ipfsecret.get(arg, passphrase) + .then(stream => {getObjects(stream);}) + .catch(err => {console.error(err);}); +} + +function encrypt(ipfsecret, arg) { + getPassphrase('encrypt') + .then(passphrase => { + addToIPFS(ipfsecret, arg, passphrase) + .then(hash => {outputResult(ipfsecret, hash);}) + .catch(err => {console.error(err);}); + }) + .catch(err => {console.error(err);}); +} + +function exec(ipfsecret, arg, command) { + if (command === 'add') { + if (yargs.argv.web) debug('Adding ' + arg + ' with web interface'); + else debug('Adding ' + arg); + add(ipfsecret, command, arg); + } + else if (command === 'get') { + debug('Retrieving ' + arg); + get(ipfsecret, arg); + } +} + +function get(ipfsecret, arg) { + getPassphrase('decrypt') + .then(passphrase => {decrypt(ipfsecret, arg, passphrase);}) + .catch(err => {console.error(err);}); +} + +function getAddOptions() { + return { + web: ['w', 'false', 'Add web interface'], + naked: ['n', 'false', 'With --web, return naked hash vs URL'], + recursive: ['r', 'false', 'Add as directory, recursively'], + hidden: ['H', 'false', 'When adding directory, include hidden files'], + }; +} + +function getAddArgs(yargs) { + let options = getAddOptions(), keys = Object.keys(options); + const argv = yargs.usage('Usage: $0 add [options] [file|dir]'); + keys.forEach(k => { + let o = options[k]; + argv.option(k, {alias: o[0], default:o[1], describe:o[2], + boolean: true}); + }); + argv.wrap(null).argv; +} + +function getArgDescs() { + return { + add: 'Encrypt & add files to IPFS', + api: 'Specify IPFS API configuration', + debug: 'Print debugging info to stderr', + gateway: 'Use this HTTP(S) gateway when returning gateway address', + get: 'Retrieve & decrypt encrypted files from IPFS', + list: 'List known HTTPS gateways', + out: 'Path where output should be stored', + route: '/ip4/' + Config.ipfs.host + '/tcp/' + Config.ipfs.port, + ver: 'Display version and exit' + }; +} + +function getArgv(ipfsecret) { + const desc = getArgDescs(); + const argv = yargs.usage('Usage: $0 [options]') + .strict() + .command('get', desc.get, function (yargs) { + const argv = yargs.usage('Usage: $0 get [multihash]') + .option('output', {alias: 'o', describe: desc.out, + type: 'string'}) + .help('help').wrap(null).argv + }) + .command('add', desc.add, function (yargs) {getAddArgs(yargs);}) + .command('list', desc.list, function (yargs) { + let count = 0; + function list(item) {console.log((count++) + ' - ' + item);} + (ipfsecret.getGatewayList()).forEach(list); + process.exit(0); + }) + .option('debug', + {alias: 'd', default: false, describe: desc.debug, + boolean: true}) + .option('api', + {alias: 'a', default: desc.route, describe: desc.api, + type: 'string'}) + .option('gateway', + {alias: 'g', default: false, describe: desc.gateway, + type: 'string'}) + .option('version', + {alias: 'v', default: false, describe: desc.ver, + boolean: true}) + .implies('gateway', 'web') + .implies('naked', 'web') + .help('help') + .wrap(null) + .argv; + return argv; +} + +function getDefaultGateway(h) { + const gPort = Config.ipfs.gatewayPort, + host = Config.ipfs.host, + idx = Config.ipfs.mainIndex, + proto = Config.ipfs.proto, + def = `${ proto }://${ host }:${gPort}/ipfs/${ h }/${ idx }`; + return def; +} + +function getIPFSecretObject() { + let ipfsecret; + if (yargs.argv.api) { + const parts = (yargs.argv.api).split('/'), + host = parts[2], port = parts[4]; + ipfsecret = new IPFSecret({host: host, port: port}); + } + else ipfsecret = new IPFSecret(); + return ipfsecret; +} + +function getMainOptions() { + const t = `/ip4/${ Config.ipfs.host }/tcp/${ Config.ipfs.port }`; + return { + debug: ['d', 'false', 'Print debugging info to stderr', true], + api: ['a', t, 'Specify IPFS API config', false, 'string'], + version: ['v', 'false', 'Display version and exit', true] + }; +} + +function getObjects(stream) { + stream.on('data', (obj) => { + if ( + (obj.content) && + !(obj.path.match(subdirRegex)) && + !(obj.path.match(indexRegex)) && + !(obj.path.match('mitm.html')) + ) { + obj.content.on('error', (err) => { + console.error('Error: Could not decrypt ' + obj.path); + }); + const hasPath = new RegExp(path.sep); + if ((obj.path).match(hasPath)) handleDir(obj); + else handleFile(obj); + } + }); +} + +function getPassphrase(mode) { + return fsStat(passPath) + .then(stats => {return checkPassFile(stats);}) + .catch(err => { + if (err.code === 'ENOENT') { + debug('No wcryptpass file found.'); + return getPassphraseFromPrompt(mode); + } + else if (err.message === Config.err.filePerms) { + debug('wcryptpass file has insecure permissions.'); + return getPassphraseFromPrompt(mode); + } + else throw err; + }); +} + +function getPassphraseFromPrompt(mode) { + return new Promise ((resolve, reject) => { + var passphrase = readline.question(Config.cmdline.passPrompt, { + hideEchoBack: true, mask: '' + }); + if (!passphrase) + reject(new Error(Config.err.passReqd)); + else if (mode === 'encrypt') { + var confirmPassphrase = readline.question( + Config.cmdline.passConf, {hideEchoBack: true, mask: ''}); + if (confirmPassphrase !== passphrase) + resolve(getPassphraseFromPrompt(mode)); + else resolve(passphrase.toString()); + } + else resolve(passphrase.toString()); + }); +} + +function handleDir(obj) { + const parsed = path.parse(obj.path), + dirParts = (parsed.dir).split(path.sep), + multihash = dirParts.shift(), + lDir = yargs.argv.output || (prog + '-' + + Config.ipfs.decryptedPrefix + '-' + multihash), + relDir = lDir + path.sep + dirParts.join(path.sep), + relative = relDir + path.sep + parsed.name + parsed.ext; + + mkdir(relDir) + .then(() => {handleObj(relative, obj);}) + .catch(err => {throw err;}); +} + +function handleFile(obj) { + const multihash = obj.path, + lFile = yargs.argv.output || (prog + '-' + + Config.ipfs.decryptedPrefix + '-' + + multihash), + writeable = fs.createWriteStream(lFile); + obj.content.pipe(writeable); + obj.content.on('finish', () => { + debug('Retrieved ' + multihash); + }); +} + +function handleObj(relative, obj) { + if (obj.content) { + const writeable = fs.createWriteStream(relative); + obj.content.pipe(writeable); + obj.content.on('finish', () => { + debug('Retrieved ' + relative); + }); + } +} + +function handleMainYargs() { + if (yargs.argv.hidden && !yargs.argv.recursive) { + console.error('--hidden only valid when used with --recursive'); + process.exit(0); + } + if (yargs.argv.api) { + var regex = new RegExp('^/ip4/.+/tcp/\\d+$'); + if (!(yargs.argv.api).match(regex)) { + console.error('--api syntax is invalid'); + process.exit(0); + } + } + if (yargs.argv.debug) IPFSecret.DEBUG = true; + if (yargs.argv.hidden) includeHidden = true; +} + +function handlePassErr(err) { + if (err.code === 'ENOENT') { + debug('No wcryptpass file found.'); + return getPassphraseFromPrompt(mode); + } + else if (err.message === Config.err.filePerms) { + debug('wcryptpass file has insecure permissions.'); + return getPassphraseFromPrompt(mode); + } + else if (err.message === Config.err.passReqd) throw err; + else throw err; +} + +function outputResult(ipfsecret, hash) { + if (yargs.argv.web) { + if (yargs.argv.gateway) process.stdout.write( + useGateway(ipfsecret, bs58.encode(hash))); + else if (yargs.argv.web && yargs.argv.naked) + process.stdout.write(bs58.encode(hash)); + else process.stdout.write(getDefaultGateway(bs58.encode(hash))); + } + else process.stdout.write(bs58.encode(hash)); +} + +function useGateway(ipfsecret, h) { + const idx = Config.ipfs.mainIndex, + list = ipfsecret.getGatewayList(); + if (list[parseInt(yargs.argv.gateway)]) + return `${ list[parseInt(yargs.argv.gateway)] }/ipfs/${ h }/${ idx }`; + else + return `${ yargs.argv.gateway }/ipfs/${ h }/${ idx }`; +} + +function validateCommand(arg, command) { + const known = {add: 1, get: 1, list: 1}; + if (!known[command]) { + console.error("\nUnknown command.\n"); + yargs.showHelp(); + process.exit(0); + } + else if (!arg) { + if (command === 'get') console.error('Multihash required'); + if (command === 'add') console.error('File or directory required'); + yargs.showHelp(); + process.exit(0); + } +} diff --git a/index.js b/index.js new file mode 100644 index 0000000..17dab7c --- /dev/null +++ b/index.js @@ -0,0 +1,52 @@ +const through = require('through2'), + Crypto = require('./lib/crypto'), + Indexer = require('./lib/indexer'), + Pkg = require('./package.json'), + Util = require('./lib/util'); + +module.exports = exports = function (ipfsOpts) { + + ipfsOpts = ipfsOpts || {}; + + const util = new Util(exports.DEBUG, ipfsOpts); + crypto = new Crypto(util), + idx = new Indexer(util), + ipfss = this; + + util.debug('Debugging enabled.'); + + ipfss.add = (path, opt) => { + if (opt.indexed) return idx.create(opt, path, crypto.init); + else return crypto.encrypt(opt, path); + }; + + ipfss.addIndexed = (path, opt) => { + if (typeof opt === 'string') opt = {passphrase: opt}; + opt.indexed = true; + return idx.create(opt, path, crypto.init); + }; + + ipfss.get = (hash, opt) => { + const stream = through.obj( + function decrypt(entry, enc, callback) { + if (entry.content) + entry = crypto.decrypt(opt, entry); + this.push(entry); + callback(); + } + ); + return crypto.decryptStream(hash, stream) + }; + + ipfss.getGatewayList = () => { + return util.cfg.ipfs.gateways + }; + + ipfss.version = exports.version = Pkg.version; + + if (process.env.IPFSECRET_ENV === 'test') { + ipfss.fonts = idx.fonts; + ipfss.css = idx.css; + ipfss.js = idx.js; + } +}; diff --git a/lib/config.json b/lib/config.json new file mode 100644 index 0000000..6f8734f --- /dev/null +++ b/lib/config.json @@ -0,0 +1,98 @@ +{ + "cmdline": { + "passConf": "Confirm passphrase: ", + "passPrompt": "Passphrase? " + }, + "err" : { + "encryptFail": "Encryption failed- ", + "filePerms": "File permissions are insecure.", + "multiString": "Please pass in the path as a String.", + "notAHash": "Result is not a recognized IPFS hash format.", + "noEncrypt": "Data is not webcrypto-crypt encrypted.", + "noErr": "Expected error but got none.", + "noHidden": "Could not detect any hidden encrypted files.", + "noRead": "Could not read dir- ", + "noStat": "Could not stat file- ", + "noSupp": " is not supported.", + "noUnlink": "Could not unlink file- ", + "objEmpty": "Object is empty.", + "passOrOpt": "Please pass in a passphrase String or options Object.", + "passReqd": "Passphrase is required.", + "pathString": "Please pass in the path as a String.", + "redacted": "(REDACTED)", + "relLinks": "Expected relative links were not found.", + "tooLarge": "This file may be too large for your browser to download.", + "zeroByte": "Skipping zero byte file- " + }, + "fonts": { + "localDir": "assets/fonts", + "localFile": "/tmp/roboto.zip", + "sourceUri": "https://google-webfonts-helper.herokuapp.com/api/fonts/roboto?download=zip&subsets=latin&variants=300,700,300italic,regular,700italic&formats=woff,woff2" + }, + "ipfs": { + "cryptoLib": { + "integrityHash": "assets/js/sha512.txt", + "path": "js/ipfsecret.js", + "source": { + "name": "dist/ipfsecret.js" + } + }, + "css": { + "base": { + "path": "styles/normalize.css", + "source": "normalize.css/normalize.css" + }, + "dialog": { + "path": "styles/dialog.css", + "source": "assets/css/dialog.css" + }, + "fonts": { + "path": "styles/fonts.css", + "source": "assets/css/fonts.css" + }, + "main": { + "path": "styles/milligram.min.css", + "source": "milligram/dist/milligram.min.css" + }, + "map": { + "path": "styles/milligram.min.css.map", + "source": "milligram/dist/milligram.min.css.map" + } + }, + "decryptedPrefix": "decrypted", + "encryptedSuffix": "wcrypt", + "fonts": { + "path": "fonts/" + }, + "footerLink": "https://ipfs.io", + "footerText": "IPFS", + "gatewayPort": 8080, + "gateways": [ + "https://gateway.ipfs.io", + "https://earth.i.ipfs.io", + "https://mercury.i.ipfs.io", + "https://gateway.ipfsstore.it:8443", + "https://scrappy.i.ipfs.io", + "https://chappy.i.ipfs.io" + ], + "host": "127.0.0.1", + "mainIndex" : "ipfsecret.html", + "mainSubdir": "/ipfsecret", + "port": 5001, + "proto": "http", + "ui": { + "browserDecryptNotSupported": "Cannot decrypt this file in the browser. Try downloading the encrypted file and decrypting it with node.js.", + "decrypt": "Decrypt", + "decrypting": "Decrypting", + "decryptUpdateDelay": 5, + "download": "Download", + "downloading": "Downloading, please wait", + "modified": "Date modified", + "name": "Name", + "offlineMode": "Offline mode detected. Attempting redirect to local IPFS gateway.", + "offlineMonitorInterval": 10000, + "passphrase": "Passphrase", + "size": "Size" + } + } +} diff --git a/lib/crypto/encrypt.js b/lib/crypto/encrypt.js new file mode 100644 index 0000000..e46ba4f --- /dev/null +++ b/lib/crypto/encrypt.js @@ -0,0 +1,126 @@ +const dir = require('node-dir'), + fs = require('fs'), + fsStat = require('util').promisify(fs.stat), + path = require('path'), + wcrypt = require('webcrypto-crypt'), + wStream = require('webcrypto-crypt/lib/node-streams.js'); + +module.exports = exports = function (util) { + + const encrypt = this; + + encrypt.init = (opt, paths) => { + const wcryptOptions = util.setWcrypt(opt); + encrypt.wcrypt = new wcrypt.cipher(wcryptOptions), + clone = JSON.parse(JSON.stringify(wcryptOptions)); + clone.material.passphrase = util.cfg.err.redacted; + util.debug('Wcrypt opt: ' + JSON.stringify(clone)); + if (paths.type === 'dir') return encryptDir(opt, paths); + else if (paths.type === 'file') return encryptFile(opt, paths); + else {throw new Error(paths.source.abs + util.cfg.err.noSupp);} + }; + + function add(opt, stream, paths, filename) { + return fsStat(filename).then(stats => { + if (stats.size > 0) + return createEntry(opt, paths, stream, filename); + else + util.debug(util.cfg.err.zeroByte + filename);return false; + }) + .catch(err => {throw err;}); + } + + function addFile(opt, paths, entries, err, stream, filename, next) { + if (err) reject(err); + if (qualifies(opt, filename)) { + return add(opt, stream, paths, filename) + .then(entry => { + if (entry) entries.push(entry); + next(); + }) + .catch(err => {throw err;}); + } + else {next();} + } + + + function createEntry(opt, paths, stream, filename) { + util.debug('Encrypting file: ' + filename); + paths = util.setFile(paths, filename); + return { + path: paths.ipfs.file + '.' + opt.suffix, + content: wStream.encrypt(encrypt.wcrypt, stream) + }; + } + + function encryptDir(opt, paths) { + util.debug('Adding directory ' + paths.source.abs); + return encrypt.wcrypt.encrypt(Buffer.from('')) + .then(() => { + return encrypt.wcrypt.encrypt(Buffer.from('')) + .then(() => {return readDir(opt, paths);}) + .catch((err) => {throw err;}); + }) + .catch((err) => {throw err;}); + } + + function encryptFile(opt, paths) { + util.debug('Adding file ' + paths.source.abs); + return encrypt.wcrypt.encrypt(Buffer.from('')) + .then(() => { + const cleartextIn = fs.createReadStream(paths.source.abs), + encryptedStream = wStream.encrypt(encrypt.wcrypt, + cleartextIn); + return oneFile(opt, paths, encryptedStream); + }) + .catch((err) => {throw err;}); + } + + function getAllEntries(opt, paths, entries, resolve, reject) { + let dirOpt; + if (opt.hidden) dirOpt = {}; + else dirOpt = {exclude: /^\./}; + dirOpt.encoding = null; // force binary + dir.readFilesStream(paths.source.abs, dirOpt, + (err, stream, filename, next) => { + addFile(opt, paths, entries, err, stream, filename, next); + }, + err => { + if (err) reject(err); + else resolve(entries); + } + ); + } + + function oneFile(opt, paths, encryptedStream) { + if (opt.indexed) { + return new Promise((resolve, reject) => { + resolve([{ + path: paths.ipfs.item + '.' + opt.suffix, + content: encryptedStream + }]); + }); + } + else { + return new Promise((resolve, reject) => { + resolve([{ + path: path.basename(paths.ipfs.item + '.' + opt.suffix), + content: encryptedStream + }]); + }); + } + } + + function qualifies(opt, filename) { + if (opt.hidden || !filename.match(/\/\./)) return true; + return false; + } + + function readDir(opt, paths, entries) { + entries = entries || []; + return new Promise((resolve, reject) => { + getAllEntries(opt, paths, entries, resolve, reject); + }); + } + +}; diff --git a/lib/crypto/index.js b/lib/crypto/index.js new file mode 100644 index 0000000..c2e7de7 --- /dev/null +++ b/lib/crypto/index.js @@ -0,0 +1,39 @@ +const wStream = require('webcrypto-crypt/lib/node-streams.js'), + Encrypt = require('./encrypt'); + +module.exports = exports = function (util) { + const crypto = this, + encrypt = new Encrypt(util); + + crypto.decrypt = (opt, entry) => { + opt = util.validateOpt(opt); + entry.content.on('error', err => { + util.debug(`${ err } ${ entry.path}`); + delete entry.content; + }); + entry.content = wStream.decrypt(opt.passphrase, entry.content); + entry.path = entry.path.replace('.' + opt.suffix, ''); + return entry; + }; + + crypto.decryptStream = (hash, stream) => { + hash = util.validateHash(hash); + return util.getFromIPFS(hash, stream); + }; + + crypto.encrypt = (opt, path) => { + opt = util.validateOpt(opt); + return util.setPaths(opt, path) + .then(paths => { + return encrypt.init(opt, paths) + .then(files => {return util.addToIPFS(opt, files);}) + .catch(err => {throw err;}); + }) + .catch(err => {throw err;}); + }; + + crypto.init = encrypt.init; + + crypto.util = util; + +}; diff --git a/lib/indexer/html.js b/lib/indexer/html.js new file mode 100644 index 0000000..935db83 --- /dev/null +++ b/lib/indexer/html.js @@ -0,0 +1,236 @@ +const fs = require('fs'), + he = require('he'), + path = require('path'), + readFile = require('util').promisify(fs.readFile); + +module.exports = exports = function (util) { + + let html = this; + mainDirRegex = new RegExp((util.cfg.ipfs.mainSubdir).replace(/^\//,'')); + + let integrityHash = ''; + readFile(__dirname + path.sep + '..' + path.sep + '..' + + path.sep + util.cfg.ipfs.cryptoLib.integrityHash) + .then((hash) => {integrityHash = hash;}) + .catch(err => {throw err;}); + + html.addRow = (item, size, date, button) => { + const formatted = util.format(size), + s = ' ', + ss = s.repeat(5); + return ` ${ ss } + ${ ss }${ s }${ item } + ${ ss }${ s }${ formatted } + ${ ss }${ s }${ date } + ${ ss }${ s }${ button } + ${ ss }`; + }; + + html.createPointers = (opt, paths) => { + return new Promise((resolve, reject) => { + resolve(createPointers(opt, paths)); + }); + }; + + html.createLink = (href, text, isLinked, isDir) => { + href = encodeURI(href); + text = he.encode(text); + let c = '', e = '', i = '', lo = '', lc = '', o = ''; + if (href && isLinked) { e = ''; lo = '';} + if (isDir) { o = '['; c = ']';i = '/' + util.cfg.ipfs.mainIndex} + return `${ lo }${ href }${ i }${ lc }${ o }${ text }${ c }${ e }`; + }; + + html.decryptButton = () => { + return ''; + }; + + html.finish = (paths, items) => { + items.push(html.getFooter()); + let p = paths.ipfs.item + '/' + util.cfg.ipfs.mainIndex; + if (paths.type === 'file') p = path.parse(paths.ipfs.item).dir + '/' + util.cfg.ipfs.mainIndex; + + return { + path: p, + content: Buffer.from(items.join("\n"), 'utf8') + }; + }; + + html.getFooter = (footerLink, footerText) => { + if (!footerLink) footerLink = util.cfg.ipfs.footerLink; + if (!footerText) footerText = util.cfg.ipfs.footerText; + let footer = ` + + + + + + `; + return footer; + }; + + html.getHeader = (opt, paths) => { + let dir = paths.ipfs.item; + if (paths.type === 'file') dir = path.parse(paths.ipfs.item).dir; + let replace = opt.directory; + if (dir.match(/\//)) replace = replace + '/'; + const titlePath = dir.replace(replace, ''), + pathParts = titlePath.split('/'); + const nav = generateNavigation(paths, pathParts); + return generateHeader(opt, nav.root, titlePath, nav.breadcrumb); + }; + + function createPointers(opt, paths) { + let dir = {}, entries = [], prev = ''; + let parts = (paths.ipfs.item).split(path.sep); + let last = parts[parts.length - 1]; + parts = parts.slice(0, parts.length - 1); + if ((paths.type === 'file') && (parts.length === 1) && + (parts[0] === opt.directory)) return []; + for (let i=0; i < parts.length; i++) { + let file = parts[i] + '/' + util.cfg.ipfs.mainIndex; + if (prev) file = prev + '/' + file; + if (parts[i+1]) dir[file] = parts[i+1]; + else dir[file] = last; + const item = html.createLink(dir[file], dir[file], true, true); + const content = Buffer.from( + getPointer(opt, prev, parts[i], dir[file]) + + html.addRow(item, '', '', '') + + html.getFooter() + , 'utf8'); + entries.push({ path: file, content: content }); + if (!prev) prev = prev + parts[i]; + else prev = prev + '/' + parts[i]; + } + return entries; + } + + function generateHeader(opt, rel, titlePath, linkPath) { + const cssName = path.basename(opt.mainCss), + d = opt.directory + '/styles/', + dialogName = path.basename(opt.dialogCss), + fontName = path.basename(opt.fontCss), + j = opt.directory + '/js/', + jsName = path.basename(opt.jsPath); + const header = ` + + + + + + + ${ titlePath } + + + + + + + + + + +
+
+

${ linkPath }

+
+
+ + + + + + + + + + `; + return header; + } + + function generateNavigation(paths, parts) { + const relative = new RegExp('^[\.,' + path.sep + ']+$'); + if ( + paths.source.clean.match(relative) + || + ((paths.type === 'file') && (parts.length === 1) && parts[0] === '') + ) { + return {breadcrumb: '', root: './'} + } + else { + let nav = [], + prev = ''; + for (let i = (parts.length - 1); i >= 0; --i) { + prev = prev + '../'; + if (i === parts.length - 1) nav.push(` ${ parts[i] }`); + else nav.push( + ` + ${ parts[i] } + `); + } + nav.reverse(); + return {breadcrumb: nav.join('/'), root: prev} + } + } + + function getPointer (opt, p, current, next) { + if (p.match(mainDirRegex)) + p = p.replace(mainDirRegex, ''); + if (current.match(mainDirRegex)) + current = ''; + let navString = p + '/' + current; + const parts = navString.split('/'); + const nav = generatePointerNav(parts); + return generateHeader(opt, nav.root, p, nav.breadcrumb); + } + + function generatePointerNav(parts) { + let nav = [], + prev = ''; + for (let i = (parts.length - 1); i >= 0; --i) { + if (parts[i]) { + if (i === parts.length - 1) nav.push(` ${ parts[i] }`); + else nav.push( + ` + ${ parts[i] } + `); + prev = prev + '../'; + } + } + nav.reverse(); + return {breadcrumb: nav.join('/'), root: prev} + } + +}; diff --git a/lib/indexer/index.js b/lib/indexer/index.js new file mode 100644 index 0000000..29757b1 --- /dev/null +++ b/lib/indexer/index.js @@ -0,0 +1,169 @@ +const dir = require('node-dir'), + fs = require('fs'), + path = require('path'), + u = require('util'), + fsStat = u.promisify(fs.stat), + readDir = u.promisify(fs.readdir), + Html = require('./html.js'), + Static = require('./static'); + +module.exports = exports = function (util) { + const indexer = this, + html = new Html(util), + static = new Static(util); + + indexer.create = (opt, path, encrypt) => { + opt = util.validateOpt(opt); + return util.setPaths(opt, path) + .then(paths => {return getAllEntries(opt, paths, encrypt);}) + .catch(err => {throw err;}); + }; + + function checkItems(opt, paths, items) { + let promises = []; + promises.push(new Promise((resolve, reject) => { + resolve(html.getHeader(opt, paths)); + })); + for (let j=0; j < items.length; j++) { + (function (item) { + promises.push(new Promise((resolve, reject) => { + let itemOnFs = paths.source.abs + '/' + item; + if (paths.type === 'file') itemOnFs = paths.source.abs; + fsStat(itemOnFs) + .then(stats => { + listItem(opt, stats, item, resolve, reject); + }) + .catch(err => {reject(util.cfg.err.noStat + err);}); + })); + })(items[j]); + } + return promises; + } + + function finish(opt, paths, encrypt, assets, indices) { + return html.createPointers(opt, paths) + .then(pointers => { + return encrypt(opt, paths) + .then(files => { + if ((files.length === 1) && pointers[0]) pointers.pop(); + const all = assets.concat(files, indices, pointers); + return util.addToIPFS(opt, all); + }) + .catch(err => {throw err;}); + }) + .catch(err => {throw err;}); + } + + function getAllEntries(opt, paths, encrypt) { + return static.getAssets(opt) + .then(assets => { + return createIndices(opt, paths) + .then(indices => { + return finish(opt, paths, encrypt, assets, indices); + }) + .catch(err => {throw err;}); + }) + .catch(err => {throw err;}); + } + + function createIndices(opt, paths) { + if (paths.type === 'dir') { + return new Promise((resolve, reject) => { + dir.subdirs(paths.source.clean, function(err, subdirs) { + if (err) reject(err); + if (subdirs) { + subdirs.push(paths.source.clean); + const promises = readSubdirs(opt, subdirs); + Promise.all(promises) + .then(indices => { + resolve(indices); + }) + .catch(err => {reject(err);}); + } + else reject(new Error(util.cfg.err.noRead + + paths.source.clean)); + }); + }); + } + else if (paths.type === 'file') { + const file = path.basename(paths.ipfs.item); + const promises = checkItems(opt, paths, [file]); + return Promise.all(promises) + .then(items => { + return html.finish(paths, items); + }) + .catch(err => {throw err;}); + } + else {throw new Error(util.cfg.err.noStat + ' ' + path);} + } + + function listDir(item, stats) { + let content = html.createLink(item, item, true, true); + return html.addRow(content, '', (new Date(stats.mtimeMs)) + .toUTCString(), ''); + } + + function listFile(opt, item, stats) { + let dButton = '', href = '', isLinked = false; + if (stats.size > 0) { + dButton = html.decryptButton(); + href = `${ item }.${ opt.suffix }`; + isLinked = true; + } + return html.addRow( + html.createLink(href, item, isLinked, false), + stats.size, + (new Date(stats.mtimeMs)).toUTCString(), + dButton + ); + } + + function listItem(opt, stats, item, resolve, reject) { + if (qualifies(opt, item, stats.size)) { + if (stats.isDirectory()) {resolve(listDir(item, stats));} + else if (stats.isFile()) {resolve(listFile(opt, item, stats));} + else reject(new Error(util.cfg.err.noStat)); + } + else {resolve('');} + } + + function qualifies(opt, item, size) { + if ((opt.hidden || (!item.match(/^\./))) && size > 0) return true; + return false; + } + + function readSubdir(opt, paths) { + return readDir(paths.source.abs).then(items => { + const promises = checkItems(opt, paths, items); + return Promise.all(promises) + .then(items => {return html.finish(paths, items);}) + .catch(err => {throw err;}); + }) + .catch(err => {throw err;}); + } + + function readSubdirs(opt, subdirs) { + let promises = []; + for (let i=0; i < subdirs.length; i++) { + (function (subdir) { + promises.push(new Promise((resolve, reject) => { + util.setPaths(opt, subdir) + .then(paths => { + readSubdir(opt, paths) + .then(indexPage => {resolve(indexPage);}) + .catch(err => {reject(err);}); + }) + .catch(err => {reject(err);}); + })); + })(subdirs[i]); + } + return promises; + } + + if (process.env.IPFSECRET_ENV === 'test') { + indexer.css = static.css; + indexer.fonts = static.fonts; + indexer.js = static.js; + } + +}; diff --git a/lib/indexer/static/css.js b/lib/indexer/static/css.js new file mode 100644 index 0000000..db460c3 --- /dev/null +++ b/lib/indexer/static/css.js @@ -0,0 +1,99 @@ +const path = require('path'), + fs = require('fs'), + util = require('util'), + readFile = util.promisify(fs.readFile); + +module.exports = exports = function (config) { + + const css = this; + + css.read = (opt) => { + const base = config.ipfs.mainSubdir + path.sep + config.ipfs.css.base.path; + const dialog = config.ipfs.mainSubdir + path.sep + config.ipfs.css.dialog.path; + const fonts = config.ipfs.mainSubdir + path.sep + config.ipfs.css.fonts.path; + const main = config.ipfs.mainSubdir + path.sep + config.ipfs.css.main.path; + const map = config.ipfs.mainSubdir + path.sep + config.ipfs.css.map.path; + + if (!opt.baseCss) + opt.baseCss = require.resolve(config.ipfs.css.base.source); + if (!opt.dialogCss) + opt.dialogCss = __dirname + path.sep + '..' + path.sep + '..' + path.sep + '..' + + path.sep + config.ipfs.css.dialog.source; + if (!opt.fontCss) + opt.fontCss = __dirname + path.sep + '..' + path.sep + '..' + path.sep + '..' + + path.sep + config.ipfs.css.fonts.source; + if (!opt.mainCss) + opt.mainCss = require.resolve(config.ipfs.css.main.source); + if (!opt.mapCss) + opt.mapCss = require.resolve(config.ipfs.css.map.source); + + return [ + {path: opt.directory + base, + content: opt.baseCss}, + {path: opt.directory + dialog, + content: opt.dialogCss}, + {path: opt.directory + fonts, + content: opt.fontCss}, + {path: opt.directory + main, + content: opt.mainCss}, + {path: opt.directory + map, + content: opt.mapCss} + ]; + }; + + css.get = (cssEntries) => { + return readFile(cssEntries[0].content) + .then(base => { + cssEntries[0].content = base; + return getFontStyles(cssEntries); + }) + .catch(err => { + throw err; + }); + }; + + function getDialog(cssEntries) { + return readFile(cssEntries[1].content) + .then(fonts => { + cssEntries[1].content = fonts; + return getMain(cssEntries); + }) + .catch(err => { + throw err; + }); + } + + function getFontStyles(cssEntries) { + return readFile(cssEntries[2].content) + .then(fonts => { + cssEntries[2].content = fonts; + return getDialog(cssEntries); + }) + .catch(err => { + throw err; + }); + } + + function getMain(cssEntries) { + return readFile(cssEntries[3].content) + .then(main => { + cssEntries[3].content = main; + return getMap(cssEntries); + }) + .catch(err => { + throw err; + }); + } + + function getMap(cssEntries) { + return readFile(cssEntries[4].content) + .then(map => { + cssEntries[4].content = map; + return cssEntries; + }) + .catch(err => { + throw err; + }); + } + +}; diff --git a/lib/indexer/static/fonts.js b/lib/indexer/static/fonts.js new file mode 100644 index 0000000..8ddff76 --- /dev/null +++ b/lib/indexer/static/fonts.js @@ -0,0 +1,80 @@ +const fs = require('fs'), + path = require('path'), + pkg = require('../../../package.json'), + util = require('util'), + readDir = util.promisify(fs.readdir), + readFile = util.promisify(fs.readFile); + +module.exports = exports = function (config) { + + const fonts = this; + + fonts.crypto = crypto; + + fonts.load = (opt) => { + return read(opt) + .then(f => { + return f; + }) + .catch(err => { + throw err; + }); + }; + + function findDir(opt) { + if (!opt.fontsDir) { + try { + const indexFile = require.resolve('ipfsecret'), + pathParts = indexFile.split(path.sep), + mainFile = pathParts.pop(), + fontPath = pathParts.join(path.sep) + path.sep + 'assets' + + path.sep + 'fonts'; + return fontPath; + } + catch (err) { + return config.fonts.localDir; + } + } + } + + function getFiles(opt, files, fontData) { + opt = opt || {directory: pkg.name}; + const subdir = config.ipfs.mainSubdir + '/' + config.ipfs.fonts.path; + let fontEntries = []; + return Promise.all(fontData) + .then((values) => { + for (let i=0; i < values.length; i++) { + fontEntries.push({ + path: opt.directory + subdir + files[i], + content: values[i] + }); + } + return fontEntries; + }) + .catch((err) => { + console.error(err); + }); + } + + function read(opt) { + opt = opt || {directory: pkg.name}; + const fontsDir = findDir(opt); + return readDir(fontsDir) + .then((files) => { + let fontData = []; + for (let i=0; i < files.length; i++) { + fontData.push(readFile(path.resolve(fontsDir) + '/' + files[i])); + } + return getFiles(opt, files, fontData); + }) + .catch(err => { + console.error(err); + }); + } + + if (process.env.IPFSECRET_ENV === 'test') { + fonts.read = read; + } + +}; + diff --git a/lib/indexer/static/index.js b/lib/indexer/static/index.js new file mode 100644 index 0000000..f0207ca --- /dev/null +++ b/lib/indexer/static/index.js @@ -0,0 +1,56 @@ +const fs = require('fs'), + fsStat = require('util').promisify(fs.stat), + he = require('he'), + pkg = require('../../../package.json'), + readFile = require('util').promisify(fs.readFile), + Css = require('./css.js'), + Fonts = require('./fonts.js'), + Js = require('./js.js'); + +module.exports = exports = function (util) { + const static = this, + fonts = new Fonts(util.cfg), + css = new Css(util.cfg), + js = new Js(util.cfg); + + static.getAssets = (opt) => { + opt = util.validateOpt(opt); + return readFiles(opt) + .then(assets => {return assets;}) + .catch(err => {throw err;}); + }; + + function getCSS(opt) { + opt = opt || {directory: pkg.name}; + const cssEntries = css.read(opt); + return css.get(cssEntries); + } + + function getFonts(opt) { + return fonts.load(opt) + .then(fontEntries => {return fontEntries;}) + .catch(err => {throw err;}); + } + + function getJs(opt) { + return js.load(opt) + .then(jsEntries => {return jsEntries;}) + .catch(err => {throw err;}); + } + + function readFiles(opt) { + return getCSS(opt).then(cssEntries => { + return getJs(opt).then(jsEntries => { + return getFonts(opt).then(fontEntries => { + return cssEntries.concat(jsEntries, fontEntries); + }).catch(err => {throw err;}); + }).catch(err => {throw err;}); + }).catch(err => {throw err;}); + } + + if (process.env.IPFSECRET_ENV === 'test') { + static.css = getCSS; + static.fonts = getFonts; + static.js = getJs; + } +}; diff --git a/lib/indexer/static/js.js b/lib/indexer/static/js.js new file mode 100644 index 0000000..c2716f5 --- /dev/null +++ b/lib/indexer/static/js.js @@ -0,0 +1,67 @@ +const path = require('path'), + pkg = require('../../../package.json'), + fs = require('fs'), + util = require('util'), + readFile = util.promisify(fs.readFile); + +module.exports = exports = function (config) { + + const js = this; + + js.load = (opt) => { + return read(opt) + .then(j => {return j;}) + .catch(err => {throw err;}); + }; + + function read(opt) { + opt = opt || {directory: pkg.name}; + const jsEntry = createMainEntry(opt); + return readFile(jsEntry.content) + .then(js => { + jsEntry.content = js; + return [jsEntry]; + }) + .catch(err => {throw err;}); + } + + function createMainEntry(opt) { + const jsLib = config.ipfs.cryptoLib, + subdir = config.ipfs.mainSubdir + '/' + jsLib.path; + if (!opt.jsPath) + opt.jsPath = __dirname + path.sep + '..' + path.sep + + '..' + path.sep + '..' + path.sep + jsLib.source.name; + return { + path: opt.directory + subdir, + content: opt.jsPath + }; + } + + function createMitmEntry(opt) { + const mitmHTML = config.ipfs.mitm, + subdir = mitmHTML.path; + if (!opt.mitmPath) + opt.mitmPath = __dirname + path.sep + '..' + path.sep + + '..' + path.sep + '..' + path.sep + mitmHTML.source; + return { + path: opt.directory + '/' + subdir, + content: opt.mitmPath + }; + } + + function createServiceWorkerEntry(opt) { + const serviceWorker = config.ipfs.serviceWorker, + subdir = serviceWorker.path; + if (!opt.serviceWorkerPath) + opt.serviceWorkerPath = __dirname + path.sep + '..' + path.sep + + '..' + path.sep + '..' + path.sep + serviceWorker.source; + return { + path: opt.directory + '/' + subdir, + content: opt.serviceWorkerPath + }; + } + + if (process.env.IPFSECRET_ENV === 'test') { + js.read = read; + } +}; diff --git a/lib/util/hashes.js b/lib/util/hashes.js new file mode 100644 index 0000000..e160266 --- /dev/null +++ b/lib/util/hashes.js @@ -0,0 +1,55 @@ +const bs58 = require('bs58'); + +module.exports = exports = function (config) { + + const esRegex = new RegExp(config.ipfs.encryptedSuffix + '$'), + h = this; + + h.findRoot = (opt, results) => { + // cover case of single file being wrapped with web UI + if (opt.indexed) { + let numEncrypted = 0; + results.forEach(r => { + if ((r.path).match(esRegex)) numEncrypted++; + }); + if (numEncrypted === 1) + return handleSingleFile(opt, results, esRegex); + } + + if (results.length === 1) + return new Buffer(bs58.decode(results[0].hash)); + else { + const last = results[results.length -1]; + if (last.path === opt.directory) + return new Buffer(bs58.decode(last.hash)); + else + throw (new Error(config.err.notAHash)); + } + }; + + h.validate = (hash) => { + if (typeof hash === 'string') hash = new Buffer(bs58.decode(hash)) + else if (!(hash instanceof Buffer)) throw new Error(config.err.notAHash); + return hash; + }; + + function handleSingleFile(opt, results, esRegex) { + let hash; + if (opt.indexed) { + results.forEach(r => { + if ((r.path) === opt.directory) { + hash = Buffer(bs58.decode(r.hash)); + } + }); + } + else { + results.forEach(r => { + if ((r.path).match(esRegex)) { + hash = Buffer(bs58.decode(r.hash)); + } + }); + } + return hash; + } + +}; diff --git a/lib/util/index.js b/lib/util/index.js new file mode 100644 index 0000000..14b6554 --- /dev/null +++ b/lib/util/index.js @@ -0,0 +1,71 @@ +const config = require('../../lib/config.json'), + ipfsAPI = require('ipfs-api'), + pkg = require('../../package.json'), + path = require('path'), + Hashes = require('./hashes.js'), + Options = require('./options.js'), + Paths = require('./paths.js'); + +module.exports = exports = function (isDebug, ipfsOpts) { + + const ipfs = ipfsAPI( + ipfsOpts.host || config.ipfs.host, + ipfsOpts.port || config.ipfs.port, + {protocol:ipfsOpts.proto || config.ipfs.proto} + ); + + const esRegex = new RegExp(config.ipfs.encryptedSuffix + '$'), + util = this, + h = new Hashes(config), + o = new Options(config, util), + p = new Paths(config); + + util.addToIPFS = (opt, assets) => { + if (opt.root) return util.root(opt, assets); + else return ipfs.files.add(assets); + } + + util.cfg = config; + + util.debug = function () { + if (isDebug) { + let msg = Array.prototype.slice.call(arguments); + msg.unshift((new Date()).toString()); + msg.unshift('[debug] '); + msg = msg.join(' '); + console.error(msg); + } + }; + + //stackoverflow.com/a/18650828 + util.format = (bytes, decimals) => { + if(bytes === 0) return '0 B'; + if (!bytes) return ''; + const k = 1024, + dm = decimals || 2, + sizes = ['B','KB','MB','GB','TB','PB','EB','ZB','YB'], + i = Math.floor(Math.log(bytes) / Math.log(k)); + return parseFloat((bytes/Math.pow(k, i)).toFixed(dm)) + ' ' + sizes[i]; + }; + + util.getFromIPFS = (hash, stream) => { + return ipfs.files.get(hash) + .then(s => {return s.pipe(stream);}) + .catch(err => {console.error(err);}); + }; + + util.root = (opt, assets) => { + return ipfs.files.add(assets) + .then(results => { + return h.findRoot(opt, results); + }) + .catch(err => {throw err;}); + }; + + util.setFile = (paths, filename) => { return p.setFile(paths, filename); }; + util.setPaths = (opt, arg) => { return p.setPaths(opt, arg); }; + util.setWcrypt = (opt) => { return o.setWcrypt(opt); }; + util.validateHash = (hash) => { return h.validate(hash); }; + util.validateOpt = (opt) => { return o.validate(opt); }; + +}; diff --git a/lib/util/options.js b/lib/util/options.js new file mode 100644 index 0000000..1831e7f --- /dev/null +++ b/lib/util/options.js @@ -0,0 +1,66 @@ +const pkg = require('../../package.json'), + path = require('path'); + +module.exports = exports = function (config, u) { + + const esRegex = new RegExp(config.ipfs.encryptedSuffix + '$'), + o = this; + + o.setWcrypt = (opt) => { + let wOpt = {}; + if (opt.wcrypt) { + wOpt = opt.wcrypt; + if (opt.passphrase) { + if (!wOpt.material) wOpt.material = {}; + wOpt.material.passphrase = opt.passphrase; + } + } + else wOpt = {material: {passphrase: opt.passphrase}}; + return wOpt; + }; + + o.validate = (opt) => { + opt = checkOptions(opt); + opt = adjustPaths(opt); + if (hasPassphrase(opt)) { + let clone = JSON.parse(JSON.stringify(opt)); + clone.passphrase = u.cfg.err.redacted; + u.debug('Options: ' + JSON.stringify(clone)); + return opt; + } + else throw new Error(config.err.passReqd); + }; + + function adjustPaths(opt) { + if (!opt.directory) opt.directory = pkg.name; + if (!opt.suffix) opt.suffix = config.ipfs.encryptedSuffix; + return opt; + } + + function checkOptions(opt) { + if (typeof opt === 'number' || Array.isArray(opt)) + throw new Error(config.err.passOrOpt); + else if (typeof opt === 'string') + return {directory: pkg.name, passphrase: opt}; + else { + return opt || { + directory: pkg.name, + hidden: true, + wcrypt: {material: {passphrase: ''}} + }; + } + } + + function hasPassphrase(opt) { + if ((!opt.passphrase && !opt.wcrypt) || + (!opt.passphrase && opt.wcrypt && !opt.wcrypt.material) || + (!opt.passphrase && opt.wcrypt && opt.wcrypt.material + && !opt.wcrypt.material.passphrase)) { + return false; + } + else { + return true; + } + } + +}; diff --git a/lib/util/paths.js b/lib/util/paths.js new file mode 100644 index 0000000..ad62e73 --- /dev/null +++ b/lib/util/paths.js @@ -0,0 +1,60 @@ +const path = require('path'), + fs = require('fs'), + fsStat = require('util').promisify(fs.stat); + +module.exports = exports = function (config) { + + const relText = ('^(\\.|\\/' + ')+'), + relRegex = new RegExp(relText), + p = this; + + p.setFile = (paths, filename) => { + paths.ipfs.file = paths.ipfs.item + '/' + + filename.replace(paths.source.abs + path.sep, ''); + paths.ipfs.file = paths.ipfs.file.replace('//', '/'); + return paths; + }; + + p.setPaths = (opt, arg) => { + if (typeof arg !== 'string') throw new Error(config.err.pathString); + return fsStat(arg) + .then(stats => { + let paths = createPaths(opt, arg, stats); + return paths; + }) + .catch(err => { + throw new Error(config.err.noStat + err); + }); + }; + + function createPaths(opt, arg, stats) { + let paths = {source: {}, ipfs: {}}; + if (stats.isDirectory()) paths.type = 'dir'; + else if (stats.isFile()) paths.type = 'file'; + else throw new Error(config.err.noStat + arg); + paths.source.orig = arg; + paths.source.clean = validate(arg); + paths.source.abs = path.resolve(paths.source.clean); + paths = setIPFSDir(opt, paths); + return paths; + } + + function validate(p) { + try {return path.format(path.parse(p));} + catch (err) {throw err;} + } + + function setIPFSDir(opt, paths) { + const normal = (path.normalize(paths.source.orig)) + .replace(relRegex, ''); + paths.ipfs.item = opt.directory + '/' + normal; + if (normal.startsWith(path.sep)) + paths.ipfs.item = opt.directory + '/' + + normal.substring(1, normal.length); + if (normal.endsWith(path.sep)) paths.ipfs.item = opt.directory + '/' + + normal.substring(0, normal.length - 1); + if ((paths.ipfs.item).match(/\/$/)) paths.ipfs.item = paths.ipfs.item.replace(/\/$/,''); + return paths; + } + +}; diff --git a/package-lock.json b/package-lock.json new file mode 100644 index 0000000..942dedf --- /dev/null +++ b/package-lock.json @@ -0,0 +1,5979 @@ +{ + "name": "ipfsecret", + "version": "0.1.0", + "lockfileVersion": 1, + "requires": true, + "dependencies": { + "JSONStream": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/JSONStream/-/JSONStream-1.3.1.tgz", + "integrity": "sha1-cH92HgHa6eFvG8+TcDt4xwlmV5o=", + "requires": { + "jsonparse": "1.3.1", + "through": "2.3.8" + } + }, + "acorn": { + "version": "4.0.13", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-4.0.13.tgz", + "integrity": "sha1-EFSVrlNh1pe9GVyCUZLhrX8lN4c=" + }, + "adm-zip": { + "version": "0.4.7", + "resolved": "https://registry.npmjs.org/adm-zip/-/adm-zip-0.4.7.tgz", + "integrity": "sha1-hgbCy/HEJs6MjsABdER/1Jtur8E=" + }, + "aggregate-error": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/aggregate-error/-/aggregate-error-1.0.0.tgz", + "integrity": "sha1-iINE2tAiCnLjr1CQYRf0h3GSX6w=", + "requires": { + "clean-stack": "1.3.0", + "indent-string": "3.2.0" + } + }, + "amdefine": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/amdefine/-/amdefine-1.0.1.tgz", + "integrity": "sha1-SlKCrBZHKek2Gbz9OtFR+BfOkfU=", + "optional": true + }, + "ansi-regex": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", + "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=" + }, + "ansi-styles": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.2.1.tgz", + "integrity": "sha1-tDLdM1i2NM914eRmQ2gkBTPB3b4=" + }, + "aproba": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/aproba/-/aproba-1.2.0.tgz", + "integrity": "sha512-Y9J6ZjXtoYh8RnXVCMOU/ttDmk1aBjunq9vO0ta5x85WDQiQfUF9sIPBITdbiiIVcBo03Hi3jMxigBtsddlXRw==" + }, + "are-we-there-yet": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/are-we-there-yet/-/are-we-there-yet-1.1.4.tgz", + "integrity": "sha1-u13KOCu5TwXhUZQ3PRb9O6HKEQ0=", + "requires": { + "delegates": "1.0.0", + "readable-stream": "2.3.3" + } + }, + "array-filter": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/array-filter/-/array-filter-0.0.1.tgz", + "integrity": "sha1-fajPLiZijtcygDWB/SH2fKzS7uw=" + }, + "array-map": { + "version": "0.0.0", + "resolved": "https://registry.npmjs.org/array-map/-/array-map-0.0.0.tgz", + "integrity": "sha1-iKK6tz0c97zVwbEYoAP2b2ZfpmI=" + }, + "array-reduce": { + "version": "0.0.0", + "resolved": "https://registry.npmjs.org/array-reduce/-/array-reduce-0.0.0.tgz", + "integrity": "sha1-FziZ0//Rx9k4PkR5Ul2+J4yrXys=" + }, + "asn1.js": { + "version": "4.9.2", + "resolved": "https://registry.npmjs.org/asn1.js/-/asn1.js-4.9.2.tgz", + "integrity": "sha512-b/OsSjvWEo8Pi8H0zsDd2P6Uqo2TK2pH8gNLSJtNLM2Db0v2QaAZ0pBQJXVjAn4gBuugeVDr7s63ZogpUIwWDg==", + "requires": { + "bn.js": "4.11.8", + "inherits": "2.0.3", + "minimalistic-assert": "1.0.0" + } + }, + "assert": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/assert/-/assert-1.4.1.tgz", + "integrity": "sha1-mZEtWRg2tab1s0XA8H7vwI/GXZE=", + "requires": { + "util": "0.10.3" + } + }, + "astw": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/astw/-/astw-2.2.0.tgz", + "integrity": "sha1-e9QXhNMkk5h66yOba04cV6hzuRc=", + "requires": { + "acorn": "4.0.13" + } + }, + "async": { + "version": "2.6.0", + "resolved": "https://registry.npmjs.org/async/-/async-2.6.0.tgz", + "integrity": "sha512-xAfGg1/NTLBBKlHFmnd7PlmUW9KhVQIUuSrYem9xzFUZy13ScvtyGGejaae9iAVRiRq9+Cx7DPFaAAhCpyxyPw==", + "requires": { + "lodash": "4.17.4" + } + }, + "babel-code-frame": { + "version": "6.26.0", + "resolved": "https://registry.npmjs.org/babel-code-frame/-/babel-code-frame-6.26.0.tgz", + "integrity": "sha1-Y/1D99weO7fONZR9uP42mj9Yx0s=", + "requires": { + "chalk": "1.1.3", + "esutils": "2.0.2", + "js-tokens": "3.0.2" + } + }, + "babel-core": { + "version": "6.26.0", + "resolved": "https://registry.npmjs.org/babel-core/-/babel-core-6.26.0.tgz", + "integrity": "sha1-rzL3izGm/O8RnIew/Y2XU/A6C7g=", + "requires": { + "babel-code-frame": "6.26.0", + "babel-generator": "6.26.0", + "babel-helpers": "6.24.1", + "babel-messages": "6.23.0", + "babel-register": "6.26.0", + "babel-runtime": "6.26.0", + "babel-template": "6.26.0", + "babel-traverse": "6.26.0", + "babel-types": "6.26.0", + "babylon": "6.18.0", + "convert-source-map": "1.5.0", + "debug": "2.6.9", + "json5": "0.5.1", + "lodash": "4.17.4", + "minimatch": "3.0.4", + "path-is-absolute": "1.0.1", + "private": "0.1.8", + "slash": "1.0.0", + "source-map": "0.5.7" + } + }, + "babel-generator": { + "version": "6.26.0", + "resolved": "https://registry.npmjs.org/babel-generator/-/babel-generator-6.26.0.tgz", + "integrity": "sha1-rBriAHC3n248odMmlhMFN3TyDcU=", + "requires": { + "babel-messages": "6.23.0", + "babel-runtime": "6.26.0", + "babel-types": "6.26.0", + "detect-indent": "4.0.0", + "jsesc": "1.3.0", + "lodash": "4.17.4", + "source-map": "0.5.7", + "trim-right": "1.0.1" + }, + "dependencies": { + "jsesc": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-1.3.0.tgz", + "integrity": "sha1-RsP+yMGJKxKwgz25vHYiF226s0s=" + } + } + }, + "babel-helper-call-delegate": { + "version": "6.24.1", + "resolved": "https://registry.npmjs.org/babel-helper-call-delegate/-/babel-helper-call-delegate-6.24.1.tgz", + "integrity": "sha1-7Oaqzdx25Bw0YfiL/Fdb0Nqi340=", + "requires": { + "babel-helper-hoist-variables": "6.24.1", + "babel-runtime": "6.26.0", + "babel-traverse": "6.26.0", + "babel-types": "6.26.0" + } + }, + "babel-helper-define-map": { + "version": "6.26.0", + "resolved": "https://registry.npmjs.org/babel-helper-define-map/-/babel-helper-define-map-6.26.0.tgz", + "integrity": "sha1-pfVtq0GiX5fstJjH66ypgZ+Vvl8=", + "requires": { + "babel-helper-function-name": "6.24.1", + "babel-runtime": "6.26.0", + "babel-types": "6.26.0", + "lodash": "4.17.4" + } + }, + "babel-helper-function-name": { + "version": "6.24.1", + "resolved": "https://registry.npmjs.org/babel-helper-function-name/-/babel-helper-function-name-6.24.1.tgz", + "integrity": "sha1-00dbjAPtmCQqJbSDUasYOZ01gKk=", + "requires": { + "babel-helper-get-function-arity": "6.24.1", + "babel-runtime": "6.26.0", + "babel-template": "6.26.0", + "babel-traverse": "6.26.0", + "babel-types": "6.26.0" + } + }, + "babel-helper-get-function-arity": { + "version": "6.24.1", + "resolved": "https://registry.npmjs.org/babel-helper-get-function-arity/-/babel-helper-get-function-arity-6.24.1.tgz", + "integrity": "sha1-j3eCqpNAfEHTqlCQj4mwMbG2hT0=", + "requires": { + "babel-runtime": "6.26.0", + "babel-types": "6.26.0" + } + }, + "babel-helper-hoist-variables": { + "version": "6.24.1", + "resolved": "https://registry.npmjs.org/babel-helper-hoist-variables/-/babel-helper-hoist-variables-6.24.1.tgz", + "integrity": "sha1-HssnaJydJVE+rbyZFKc/VAi+enY=", + "requires": { + "babel-runtime": "6.26.0", + "babel-types": "6.26.0" + } + }, + "babel-helper-optimise-call-expression": { + "version": "6.24.1", + "resolved": "https://registry.npmjs.org/babel-helper-optimise-call-expression/-/babel-helper-optimise-call-expression-6.24.1.tgz", + "integrity": "sha1-96E0J7qfc/j0+pk8VKl4gtEkQlc=", + "requires": { + "babel-runtime": "6.26.0", + "babel-types": "6.26.0" + } + }, + "babel-helper-regex": { + "version": "6.26.0", + "resolved": "https://registry.npmjs.org/babel-helper-regex/-/babel-helper-regex-6.26.0.tgz", + "integrity": "sha1-MlxZ+QL4LyS3T6zu0DY5VPZJXnI=", + "requires": { + "babel-runtime": "6.26.0", + "babel-types": "6.26.0", + "lodash": "4.17.4" + } + }, + "babel-helper-replace-supers": { + "version": "6.24.1", + "resolved": "https://registry.npmjs.org/babel-helper-replace-supers/-/babel-helper-replace-supers-6.24.1.tgz", + "integrity": "sha1-v22/5Dk40XNpohPKiov3S2qQqxo=", + "requires": { + "babel-helper-optimise-call-expression": "6.24.1", + "babel-messages": "6.23.0", + "babel-runtime": "6.26.0", + "babel-template": "6.26.0", + "babel-traverse": "6.26.0", + "babel-types": "6.26.0" + } + }, + "babel-helpers": { + "version": "6.24.1", + "resolved": "https://registry.npmjs.org/babel-helpers/-/babel-helpers-6.24.1.tgz", + "integrity": "sha1-NHHenK7DiOXIUOWX5Yom3fN2ArI=", + "requires": { + "babel-runtime": "6.26.0", + "babel-template": "6.26.0" + } + }, + "babel-messages": { + "version": "6.23.0", + "resolved": "https://registry.npmjs.org/babel-messages/-/babel-messages-6.23.0.tgz", + "integrity": "sha1-8830cDhYA1sqKVHG7F7fbGLyYw4=", + "requires": { + "babel-runtime": "6.26.0" + } + }, + "babel-plugin-check-es2015-constants": { + "version": "6.22.0", + "resolved": "https://registry.npmjs.org/babel-plugin-check-es2015-constants/-/babel-plugin-check-es2015-constants-6.22.0.tgz", + "integrity": "sha1-NRV7EBQm/S/9PaP3XH0ekYNbv4o=", + "requires": { + "babel-runtime": "6.26.0" + } + }, + "babel-plugin-transform-es2015-arrow-functions": { + "version": "6.22.0", + "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-arrow-functions/-/babel-plugin-transform-es2015-arrow-functions-6.22.0.tgz", + "integrity": "sha1-RSaSy3EdX3ncf4XkQM5BufJE0iE=", + "requires": { + "babel-runtime": "6.26.0" + } + }, + "babel-plugin-transform-es2015-block-scoped-functions": { + "version": "6.22.0", + "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-block-scoped-functions/-/babel-plugin-transform-es2015-block-scoped-functions-6.22.0.tgz", + "integrity": "sha1-u8UbSflk1wy42OC5ToICRs46YUE=", + "requires": { + "babel-runtime": "6.26.0" + } + }, + "babel-plugin-transform-es2015-block-scoping": { + "version": "6.26.0", + "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-block-scoping/-/babel-plugin-transform-es2015-block-scoping-6.26.0.tgz", + "integrity": "sha1-1w9SmcEwjQXBL0Y4E7CgnnOxiV8=", + "requires": { + "babel-runtime": "6.26.0", + "babel-template": "6.26.0", + "babel-traverse": "6.26.0", + "babel-types": "6.26.0", + "lodash": "4.17.4" + } + }, + "babel-plugin-transform-es2015-classes": { + "version": "6.24.1", + "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-classes/-/babel-plugin-transform-es2015-classes-6.24.1.tgz", + "integrity": "sha1-WkxYpQyclGHlZLSyo7+ryXolhNs=", + "requires": { + "babel-helper-define-map": "6.26.0", + "babel-helper-function-name": "6.24.1", + "babel-helper-optimise-call-expression": "6.24.1", + "babel-helper-replace-supers": "6.24.1", + "babel-messages": "6.23.0", + "babel-runtime": "6.26.0", + "babel-template": "6.26.0", + "babel-traverse": "6.26.0", + "babel-types": "6.26.0" + } + }, + "babel-plugin-transform-es2015-computed-properties": { + "version": "6.24.1", + "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-computed-properties/-/babel-plugin-transform-es2015-computed-properties-6.24.1.tgz", + "integrity": "sha1-b+Ko0WiV1WNPTNmZttNICjCBWbM=", + "requires": { + "babel-runtime": "6.26.0", + "babel-template": "6.26.0" + } + }, + "babel-plugin-transform-es2015-destructuring": { + "version": "6.23.0", + "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-destructuring/-/babel-plugin-transform-es2015-destructuring-6.23.0.tgz", + "integrity": "sha1-mXux8auWf2gtKwh2/jWNYOdlxW0=", + "requires": { + "babel-runtime": "6.26.0" + } + }, + "babel-plugin-transform-es2015-duplicate-keys": { + "version": "6.24.1", + "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-duplicate-keys/-/babel-plugin-transform-es2015-duplicate-keys-6.24.1.tgz", + "integrity": "sha1-c+s9MQypaePvnskcU3QabxV2Qj4=", + "requires": { + "babel-runtime": "6.26.0", + "babel-types": "6.26.0" + } + }, + "babel-plugin-transform-es2015-for-of": { + "version": "6.23.0", + "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-for-of/-/babel-plugin-transform-es2015-for-of-6.23.0.tgz", + "integrity": "sha1-9HyVsrYT3x0+zC/bdXNiPHUkhpE=", + "requires": { + "babel-runtime": "6.26.0" + } + }, + "babel-plugin-transform-es2015-function-name": { + "version": "6.24.1", + "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-function-name/-/babel-plugin-transform-es2015-function-name-6.24.1.tgz", + "integrity": "sha1-g0yJhTvDaxrw86TF26qU/Y6sqos=", + "requires": { + "babel-helper-function-name": "6.24.1", + "babel-runtime": "6.26.0", + "babel-types": "6.26.0" + } + }, + "babel-plugin-transform-es2015-literals": { + "version": "6.22.0", + "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-literals/-/babel-plugin-transform-es2015-literals-6.22.0.tgz", + "integrity": "sha1-T1SgLWzWbPkVKAAZox0xklN3yi4=", + "requires": { + "babel-runtime": "6.26.0" + } + }, + "babel-plugin-transform-es2015-modules-amd": { + "version": "6.24.1", + "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-modules-amd/-/babel-plugin-transform-es2015-modules-amd-6.24.1.tgz", + "integrity": "sha1-Oz5UAXI5hC1tGcMBHEvS8AoA0VQ=", + "requires": { + "babel-plugin-transform-es2015-modules-commonjs": "6.26.0", + "babel-runtime": "6.26.0", + "babel-template": "6.26.0" + } + }, + "babel-plugin-transform-es2015-modules-commonjs": { + "version": "6.26.0", + "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-modules-commonjs/-/babel-plugin-transform-es2015-modules-commonjs-6.26.0.tgz", + "integrity": "sha1-DYOUApt9xqvhqX7xgeAHWN0uXYo=", + "requires": { + "babel-plugin-transform-strict-mode": "6.24.1", + "babel-runtime": "6.26.0", + "babel-template": "6.26.0", + "babel-types": "6.26.0" + } + }, + "babel-plugin-transform-es2015-modules-systemjs": { + "version": "6.24.1", + "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-modules-systemjs/-/babel-plugin-transform-es2015-modules-systemjs-6.24.1.tgz", + "integrity": "sha1-/4mhQrkRmpBhlfXxBuzzBdlAfSM=", + "requires": { + "babel-helper-hoist-variables": "6.24.1", + "babel-runtime": "6.26.0", + "babel-template": "6.26.0" + } + }, + "babel-plugin-transform-es2015-modules-umd": { + "version": "6.24.1", + "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-modules-umd/-/babel-plugin-transform-es2015-modules-umd-6.24.1.tgz", + "integrity": "sha1-rJl+YoXNGO1hdq22B9YCNErThGg=", + "requires": { + "babel-plugin-transform-es2015-modules-amd": "6.24.1", + "babel-runtime": "6.26.0", + "babel-template": "6.26.0" + } + }, + "babel-plugin-transform-es2015-object-super": { + "version": "6.24.1", + "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-object-super/-/babel-plugin-transform-es2015-object-super-6.24.1.tgz", + "integrity": "sha1-JM72muIcuDp/hgPa0CH1cusnj40=", + "requires": { + "babel-helper-replace-supers": "6.24.1", + "babel-runtime": "6.26.0" + } + }, + "babel-plugin-transform-es2015-parameters": { + "version": "6.24.1", + "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-parameters/-/babel-plugin-transform-es2015-parameters-6.24.1.tgz", + "integrity": "sha1-V6w1GrScrxSpfNE7CfZv3wpiXys=", + "requires": { + "babel-helper-call-delegate": "6.24.1", + "babel-helper-get-function-arity": "6.24.1", + "babel-runtime": "6.26.0", + "babel-template": "6.26.0", + "babel-traverse": "6.26.0", + "babel-types": "6.26.0" + } + }, + "babel-plugin-transform-es2015-shorthand-properties": { + "version": "6.24.1", + "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-shorthand-properties/-/babel-plugin-transform-es2015-shorthand-properties-6.24.1.tgz", + "integrity": "sha1-JPh11nIch2YbvZmkYi5R8U3jiqA=", + "requires": { + "babel-runtime": "6.26.0", + "babel-types": "6.26.0" + } + }, + "babel-plugin-transform-es2015-spread": { + "version": "6.22.0", + "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-spread/-/babel-plugin-transform-es2015-spread-6.22.0.tgz", + "integrity": "sha1-1taKmfia7cRTbIGlQujdnxdG+NE=", + "requires": { + "babel-runtime": "6.26.0" + } + }, + "babel-plugin-transform-es2015-sticky-regex": { + "version": "6.24.1", + "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-sticky-regex/-/babel-plugin-transform-es2015-sticky-regex-6.24.1.tgz", + "integrity": "sha1-AMHNsaynERLN8M9hJsLta0V8zbw=", + "requires": { + "babel-helper-regex": "6.26.0", + "babel-runtime": "6.26.0", + "babel-types": "6.26.0" + } + }, + "babel-plugin-transform-es2015-template-literals": { + "version": "6.22.0", + "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-template-literals/-/babel-plugin-transform-es2015-template-literals-6.22.0.tgz", + "integrity": "sha1-qEs0UPfp+PH2g51taH2oS7EjbY0=", + "requires": { + "babel-runtime": "6.26.0" + } + }, + "babel-plugin-transform-es2015-typeof-symbol": { + "version": "6.23.0", + "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-typeof-symbol/-/babel-plugin-transform-es2015-typeof-symbol-6.23.0.tgz", + "integrity": "sha1-3sCfHN3/lLUqxz1QXITfWdzOs3I=", + "requires": { + "babel-runtime": "6.26.0" + } + }, + "babel-plugin-transform-es2015-unicode-regex": { + "version": "6.24.1", + "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-unicode-regex/-/babel-plugin-transform-es2015-unicode-regex-6.24.1.tgz", + "integrity": "sha1-04sS9C6nMj9yk4fxinxa4frrNek=", + "requires": { + "babel-helper-regex": "6.26.0", + "babel-runtime": "6.26.0", + "regexpu-core": "2.0.0" + } + }, + "babel-plugin-transform-regenerator": { + "version": "6.26.0", + "resolved": "https://registry.npmjs.org/babel-plugin-transform-regenerator/-/babel-plugin-transform-regenerator-6.26.0.tgz", + "integrity": "sha1-4HA2lvveJ/Cj78rPi03KL3s6jy8=", + "requires": { + "regenerator-transform": "0.10.1" + } + }, + "babel-plugin-transform-strict-mode": { + "version": "6.24.1", + "resolved": "https://registry.npmjs.org/babel-plugin-transform-strict-mode/-/babel-plugin-transform-strict-mode-6.24.1.tgz", + "integrity": "sha1-1fr3qleKZbvlkc9e2uBKDGcCB1g=", + "requires": { + "babel-runtime": "6.26.0", + "babel-types": "6.26.0" + } + }, + "babel-preset-es2015": { + "version": "6.24.1", + "resolved": "https://registry.npmjs.org/babel-preset-es2015/-/babel-preset-es2015-6.24.1.tgz", + "integrity": "sha1-1EBQ1rwsn+6nAqrzjXJ6AhBTiTk=", + "requires": { + "babel-plugin-check-es2015-constants": "6.22.0", + "babel-plugin-transform-es2015-arrow-functions": "6.22.0", + "babel-plugin-transform-es2015-block-scoped-functions": "6.22.0", + "babel-plugin-transform-es2015-block-scoping": "6.26.0", + "babel-plugin-transform-es2015-classes": "6.24.1", + "babel-plugin-transform-es2015-computed-properties": "6.24.1", + "babel-plugin-transform-es2015-destructuring": "6.23.0", + "babel-plugin-transform-es2015-duplicate-keys": "6.24.1", + "babel-plugin-transform-es2015-for-of": "6.23.0", + "babel-plugin-transform-es2015-function-name": "6.24.1", + "babel-plugin-transform-es2015-literals": "6.22.0", + "babel-plugin-transform-es2015-modules-amd": "6.24.1", + "babel-plugin-transform-es2015-modules-commonjs": "6.26.0", + "babel-plugin-transform-es2015-modules-systemjs": "6.24.1", + "babel-plugin-transform-es2015-modules-umd": "6.24.1", + "babel-plugin-transform-es2015-object-super": "6.24.1", + "babel-plugin-transform-es2015-parameters": "6.24.1", + "babel-plugin-transform-es2015-shorthand-properties": "6.24.1", + "babel-plugin-transform-es2015-spread": "6.22.0", + "babel-plugin-transform-es2015-sticky-regex": "6.24.1", + "babel-plugin-transform-es2015-template-literals": "6.22.0", + "babel-plugin-transform-es2015-typeof-symbol": "6.23.0", + "babel-plugin-transform-es2015-unicode-regex": "6.24.1", + "babel-plugin-transform-regenerator": "6.26.0" + } + }, + "babel-register": { + "version": "6.26.0", + "resolved": "https://registry.npmjs.org/babel-register/-/babel-register-6.26.0.tgz", + "integrity": "sha1-btAhFz4vy0htestFxgCahW9kcHE=", + "requires": { + "babel-core": "6.26.0", + "babel-runtime": "6.26.0", + "core-js": "2.5.1", + "home-or-tmp": "2.0.0", + "lodash": "4.17.4", + "mkdirp": "0.5.1", + "source-map-support": "0.4.18" + } + }, + "babel-runtime": { + "version": "6.26.0", + "resolved": "https://registry.npmjs.org/babel-runtime/-/babel-runtime-6.26.0.tgz", + "integrity": "sha1-llxwWGaOgrVde/4E/yM3vItWR/4=", + "requires": { + "core-js": "2.5.1", + "regenerator-runtime": "0.11.0" + } + }, + "babel-template": { + "version": "6.26.0", + "resolved": "https://registry.npmjs.org/babel-template/-/babel-template-6.26.0.tgz", + "integrity": "sha1-3gPi0WOWsGn0bdn/+FIfsaDjXgI=", + "requires": { + "babel-runtime": "6.26.0", + "babel-traverse": "6.26.0", + "babel-types": "6.26.0", + "babylon": "6.18.0", + "lodash": "4.17.4" + } + }, + "babel-traverse": { + "version": "6.26.0", + "resolved": "https://registry.npmjs.org/babel-traverse/-/babel-traverse-6.26.0.tgz", + "integrity": "sha1-RqnL1+3MYsjlwGTi0tjQ9ANXZu4=", + "requires": { + "babel-code-frame": "6.26.0", + "babel-messages": "6.23.0", + "babel-runtime": "6.26.0", + "babel-types": "6.26.0", + "babylon": "6.18.0", + "debug": "2.6.9", + "globals": "9.18.0", + "invariant": "2.2.2", + "lodash": "4.17.4" + } + }, + "babel-types": { + "version": "6.26.0", + "resolved": "https://registry.npmjs.org/babel-types/-/babel-types-6.26.0.tgz", + "integrity": "sha1-o7Bz+Uq0nrb6Vc1lInozQ4BjJJc=", + "requires": { + "babel-runtime": "6.26.0", + "esutils": "2.0.2", + "lodash": "4.17.4", + "to-fast-properties": "1.0.3" + } + }, + "babelify": { + "version": "7.3.0", + "resolved": "https://registry.npmjs.org/babelify/-/babelify-7.3.0.tgz", + "integrity": "sha1-qlau3nBn/XvVSWZu4W3ChQh+iOU=", + "requires": { + "babel-core": "6.26.0", + "object-assign": "4.1.1" + } + }, + "babylon": { + "version": "6.18.0", + "resolved": "https://registry.npmjs.org/babylon/-/babylon-6.18.0.tgz", + "integrity": "sha512-q/UEjfGJ2Cm3oKV71DJz9d25TPnq5rhBVL2Q4fA5wcC3jcrdn7+SssEybFIxwAvvP+YCsCYNKughoF33GxgycQ==" + }, + "balanced-match": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz", + "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=" + }, + "base-x": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/base-x/-/base-x-3.0.2.tgz", + "integrity": "sha1-v4c4YbdRQnm3lp80CSnquHwR0TA=", + "requires": { + "safe-buffer": "5.1.1" + } + }, + "base64-js": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.2.1.tgz", + "integrity": "sha512-dwVUVIXsBZXwTuwnXI9RK8sBmgq09NDHzyR9SAph9eqk76gKK2JSQmZARC2zRC81JC2QTtxD0ARU5qTS25gIGw==" + }, + "binary-split": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/binary-split/-/binary-split-1.0.3.tgz", + "integrity": "sha1-yqiKyNhZ0zFw9fHOa0xZCHn3UCY=", + "requires": { + "through2": "2.0.3" + } + }, + "bindexof": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/bindexof/-/bindexof-1.0.1.tgz", + "integrity": "sha1-3AVeFKn3WSUNsLNf9ybhZF7v++I=" + }, + "bindings": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/bindings/-/bindings-1.3.0.tgz", + "integrity": "sha512-DpLh5EzMR2kzvX1KIlVC0VkC3iZtHKTgdtZ0a3pglBZdaQFjt5S9g9xd1lE+YvXyfd6mtCeRnrUfOLYiTMlNSw==" + }, + "bip66": { + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/bip66/-/bip66-1.1.5.tgz", + "integrity": "sha1-AfqHSHhcpwlV1QESF9GzE5lpyiI=", + "requires": { + "safe-buffer": "5.1.1" + } + }, + "bl": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/bl/-/bl-1.2.1.tgz", + "integrity": "sha1-ysMo977kVzDUBLaSID/LWQ4XLV4=", + "requires": { + "readable-stream": "2.3.3" + } + }, + "blakejs": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/blakejs/-/blakejs-1.1.0.tgz", + "integrity": "sha1-ad+S75U6qIylGjLfarHFShVfx6U=" + }, + "blob-to-buffer": { + "version": "1.2.6", + "resolved": "https://registry.npmjs.org/blob-to-buffer/-/blob-to-buffer-1.2.6.tgz", + "integrity": "sha1-CJrCZMaGtz6tbFOaSEqAA7+7IDM=" + }, + "bn.js": { + "version": "4.11.8", + "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.11.8.tgz", + "integrity": "sha512-ItfYfPLkWHUjckQCk8xC+LwxgK8NYcXywGigJgSwOP8Y2iyWT4f2vsZnoOXTTbo+o5yXmIUJ4gn5538SO5S3gA==" + }, + "brace-expansion": { + "version": "1.1.8", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.8.tgz", + "integrity": "sha1-wHshHHyVLsH479Uad+8NHTmQopI=", + "requires": { + "balanced-match": "1.0.0", + "concat-map": "0.0.1" + } + }, + "brfs": { + "version": "1.4.3", + "resolved": "https://registry.npmjs.org/brfs/-/brfs-1.4.3.tgz", + "integrity": "sha1-22ddb16SPm3wh/ylhZyQkKrtMhY=", + "requires": { + "quote-stream": "1.0.2", + "resolve": "1.5.0", + "static-module": "1.5.0", + "through2": "2.0.3" + } + }, + "brorand": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/brorand/-/brorand-1.1.0.tgz", + "integrity": "sha1-EsJe/kCkXjwyPrhnWgoM5XsiNx8=" + }, + "browser-pack": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/browser-pack/-/browser-pack-6.0.2.tgz", + "integrity": "sha1-+GzWzvT1MAyOY+B6TVEvZfv/RTE=", + "requires": { + "JSONStream": "1.3.1", + "combine-source-map": "0.7.2", + "defined": "1.0.0", + "through2": "2.0.3", + "umd": "3.0.1" + } + }, + "browser-resolve": { + "version": "1.11.2", + "resolved": "https://registry.npmjs.org/browser-resolve/-/browser-resolve-1.11.2.tgz", + "integrity": "sha1-j/CbCixCFxihBRwmCzLkj0QpOM4=", + "requires": { + "resolve": "1.1.7" + }, + "dependencies": { + "resolve": { + "version": "1.1.7", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.1.7.tgz", + "integrity": "sha1-IDEU2CrSxe2ejgQRs5ModeiJ6Xs=" + } + } + }, + "browser-stdout": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/browser-stdout/-/browser-stdout-1.3.0.tgz", + "integrity": "sha1-81HTKWnTL6XXpVZxVCY9korjvR8=", + "dev": true + }, + "browserify": { + "version": "14.5.0", + "resolved": "https://registry.npmjs.org/browserify/-/browserify-14.5.0.tgz", + "integrity": "sha512-gKfOsNQv/toWz+60nSPfYzuwSEdzvV2WdxrVPUbPD/qui44rAkB3t3muNtmmGYHqrG56FGwX9SUEQmzNLAeS7g==", + "requires": { + "JSONStream": "1.3.1", + "assert": "1.4.1", + "browser-pack": "6.0.2", + "browser-resolve": "1.11.2", + "browserify-zlib": "0.2.0", + "buffer": "5.0.8", + "cached-path-relative": "1.0.1", + "concat-stream": "1.5.2", + "console-browserify": "1.1.0", + "constants-browserify": "1.0.0", + "crypto-browserify": "3.12.0", + "defined": "1.0.0", + "deps-sort": "2.0.0", + "domain-browser": "1.1.7", + "duplexer2": "0.1.4", + "events": "1.1.1", + "glob": "7.1.2", + "has": "1.0.1", + "htmlescape": "1.1.1", + "https-browserify": "1.0.0", + "inherits": "2.0.3", + "insert-module-globals": "7.0.1", + "labeled-stream-splicer": "2.0.0", + "module-deps": "4.1.1", + "os-browserify": "0.3.0", + "parents": "1.0.1", + "path-browserify": "0.0.0", + "process": "0.11.10", + "punycode": "1.4.1", + "querystring-es3": "0.2.1", + "read-only-stream": "2.0.0", + "readable-stream": "2.3.3", + "resolve": "1.5.0", + "shasum": "1.0.2", + "shell-quote": "1.6.1", + "stream-browserify": "2.0.1", + "stream-http": "2.7.2", + "string_decoder": "1.0.3", + "subarg": "1.0.0", + "syntax-error": "1.3.0", + "through2": "2.0.3", + "timers-browserify": "1.4.2", + "tty-browserify": "0.0.0", + "url": "0.11.0", + "util": "0.10.3", + "vm-browserify": "0.0.4", + "xtend": "4.0.1" + } + }, + "browserify-aes": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/browserify-aes/-/browserify-aes-1.1.1.tgz", + "integrity": "sha512-UGnTYAnB2a3YuYKIRy1/4FB2HdM866E0qC46JXvVTYKlBlZlnvfpSfY6OKfXZAkv70eJ2a1SqzpAo5CRhZGDFg==", + "requires": { + "buffer-xor": "1.0.3", + "cipher-base": "1.0.4", + "create-hash": "1.1.3", + "evp_bytestokey": "1.0.3", + "inherits": "2.0.3", + "safe-buffer": "5.1.1" + } + }, + "browserify-cipher": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/browserify-cipher/-/browserify-cipher-1.0.0.tgz", + "integrity": "sha1-mYgkSHS/XtTijalWZtzWasj8Njo=", + "requires": { + "browserify-aes": "1.1.1", + "browserify-des": "1.0.0", + "evp_bytestokey": "1.0.3" + } + }, + "browserify-des": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/browserify-des/-/browserify-des-1.0.0.tgz", + "integrity": "sha1-2qJ3cXRwki7S/hhZQRihdUOXId0=", + "requires": { + "cipher-base": "1.0.4", + "des.js": "1.0.0", + "inherits": "2.0.3" + } + }, + "browserify-rsa": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/browserify-rsa/-/browserify-rsa-4.0.1.tgz", + "integrity": "sha1-IeCr+vbyApzy+vsTNWenAdQTVSQ=", + "requires": { + "bn.js": "4.11.8", + "randombytes": "2.0.5" + } + }, + "browserify-sign": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/browserify-sign/-/browserify-sign-4.0.4.tgz", + "integrity": "sha1-qk62jl17ZYuqa/alfmMMvXqT0pg=", + "requires": { + "bn.js": "4.11.8", + "browserify-rsa": "4.0.1", + "create-hash": "1.1.3", + "create-hmac": "1.1.6", + "elliptic": "6.4.0", + "inherits": "2.0.3", + "parse-asn1": "5.1.0" + } + }, + "browserify-zlib": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/browserify-zlib/-/browserify-zlib-0.2.0.tgz", + "integrity": "sha512-Z942RysHXmJrhqk88FmKBVq/v5tqmSkDz7p54G/MGyjMnCFFnC79XWNbg+Vta8W6Wb2qtSZTSxIGkJrRpCFEiA==", + "requires": { + "pako": "1.0.6" + } + }, + "bs58": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/bs58/-/bs58-4.0.1.tgz", + "integrity": "sha1-vhYedsNU9veIrkBx9j806MTwpCo=", + "requires": { + "base-x": "3.0.2" + } + }, + "buffer": { + "version": "5.0.8", + "resolved": "https://registry.npmjs.org/buffer/-/buffer-5.0.8.tgz", + "integrity": "sha512-xXvjQhVNz50v2nPeoOsNqWCLGfiv4ji/gXZM28jnVwdLJxH4mFyqgqCKfaK9zf1KUbG6zTkjLOy7ou+jSMarGA==", + "requires": { + "base64-js": "1.2.1", + "ieee754": "1.1.8" + } + }, + "buffer-equal": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/buffer-equal/-/buffer-equal-0.0.1.tgz", + "integrity": "sha1-kbx0sR6kBbyRa8aqkI+q+ltKrEs=" + }, + "buffer-loader": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/buffer-loader/-/buffer-loader-0.0.1.tgz", + "integrity": "sha1-TWd8qS3YiTEIeLAqL7z6txICTPI=" + }, + "buffer-xor": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/buffer-xor/-/buffer-xor-1.0.3.tgz", + "integrity": "sha1-JuYe0UIvtw3ULm42cp7VHYVf6Nk=" + }, + "builtin-modules": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/builtin-modules/-/builtin-modules-1.1.1.tgz", + "integrity": "sha1-Jw8HbFpywC9bZaR9+Uxf46J4iS8=" + }, + "builtin-status-codes": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/builtin-status-codes/-/builtin-status-codes-3.0.0.tgz", + "integrity": "sha1-hZgoeOIbmOHGZCXgPQF0eI9Wnug=" + }, + "cached-path-relative": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/cached-path-relative/-/cached-path-relative-1.0.1.tgz", + "integrity": "sha1-0JxLUoAKpMB44t2BqGmqyQ0uVOc=" + }, + "camelcase": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-3.0.0.tgz", + "integrity": "sha1-MvxLn82vhF/N9+c7uXysImHwqwo=" + }, + "capture-stack-trace": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/capture-stack-trace/-/capture-stack-trace-1.0.0.tgz", + "integrity": "sha1-Sm+gc5nCa7pH8LJJa00PtAjFVQ0=" + }, + "chalk": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz", + "integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=", + "requires": { + "ansi-styles": "2.2.1", + "escape-string-regexp": "1.0.5", + "has-ansi": "2.0.0", + "strip-ansi": "3.0.1", + "supports-color": "2.0.0" + } + }, + "chop": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/chop/-/chop-0.0.1.tgz", + "integrity": "sha1-JsIQkZ/4frMg6mfhHVKO7vvOYKg=" + }, + "chownr": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/chownr/-/chownr-1.0.1.tgz", + "integrity": "sha1-4qdQQqlVGQi+vSW4Uj1fl2nXkYE=" + }, + "cids": { + "version": "0.5.2", + "resolved": "https://registry.npmjs.org/cids/-/cids-0.5.2.tgz", + "integrity": "sha512-ymyC9kV8iKgvn+MU44glekHKMDbfx7hUh1YRNDJ4ZzBQspFamRvmDlbH5jjHp9LwwH1vvJuV/rcy1gWJeSVcIw==", + "requires": { + "multibase": "0.3.4", + "multicodec": "0.2.5", + "multihashes": "0.4.12" + } + }, + "cipher-base": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/cipher-base/-/cipher-base-1.0.4.tgz", + "integrity": "sha512-Kkht5ye6ZGmwv40uUDZztayT2ThLQGfnj/T71N/XzeZeo3nf8foyW7zGTsPYkEya3m5f3cAypH+qe7YOrM1U2Q==", + "requires": { + "inherits": "2.0.3", + "safe-buffer": "5.1.1" + } + }, + "clean-stack": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/clean-stack/-/clean-stack-1.3.0.tgz", + "integrity": "sha1-noIVAa6XmYbEax1m0tQy2y/UrjE=" + }, + "cliui": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-3.2.0.tgz", + "integrity": "sha1-EgYBU3qRbSmUD5NNo7SNWFo5IT0=", + "requires": { + "string-width": "1.0.2", + "strip-ansi": "3.0.1", + "wrap-ansi": "2.1.0" + } + }, + "code-point-at": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/code-point-at/-/code-point-at-1.1.0.tgz", + "integrity": "sha1-DQcLTQQ6W+ozovGkDi7bPZpMz3c=" + }, + "combine-source-map": { + "version": "0.7.2", + "resolved": "https://registry.npmjs.org/combine-source-map/-/combine-source-map-0.7.2.tgz", + "integrity": "sha1-CHAxKFazB6h8xKxIbzqaYq7MwJ4=", + "requires": { + "convert-source-map": "1.1.3", + "inline-source-map": "0.6.2", + "lodash.memoize": "3.0.4", + "source-map": "0.5.7" + }, + "dependencies": { + "convert-source-map": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.1.3.tgz", + "integrity": "sha1-SCnId+n+SbMWHzvzZziI4gRpmGA=" + } + } + }, + "commander": { + "version": "2.9.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-2.9.0.tgz", + "integrity": "sha1-nJkJQXbhIkDLItbFFGCYQA/g99Q=", + "dev": true, + "requires": { + "graceful-readlink": "1.0.1" + } + }, + "concat-map": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", + "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=" + }, + "concat-stream": { + "version": "1.5.2", + "resolved": "https://registry.npmjs.org/concat-stream/-/concat-stream-1.5.2.tgz", + "integrity": "sha1-cIl4Yk2FavQaWnQd790mHadSwmY=", + "requires": { + "inherits": "2.0.3", + "readable-stream": "2.0.6", + "typedarray": "0.0.6" + }, + "dependencies": { + "readable-stream": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.0.6.tgz", + "integrity": "sha1-j5A0HmilPMySh4jaz80Rs265t44=", + "requires": { + "core-util-is": "1.0.2", + "inherits": "2.0.3", + "isarray": "1.0.0", + "process-nextick-args": "1.0.7", + "string_decoder": "0.10.31", + "util-deprecate": "1.0.2" + } + }, + "string_decoder": { + "version": "0.10.31", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-0.10.31.tgz", + "integrity": "sha1-YuIDvEF2bGwoyfyEMB2rHFMQ+pQ=" + } + } + }, + "console-browserify": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/console-browserify/-/console-browserify-1.1.0.tgz", + "integrity": "sha1-8CQcRXMKn8YyOyBtvzjtx0HQuxA=", + "requires": { + "date-now": "0.1.4" + } + }, + "console-control-strings": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/console-control-strings/-/console-control-strings-1.1.0.tgz", + "integrity": "sha1-PXz0Rk22RG6mRL9LOVB/mFEAjo4=" + }, + "constants-browserify": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/constants-browserify/-/constants-browserify-1.0.0.tgz", + "integrity": "sha1-wguW2MYXdIqvHBYCF2DNJ/y4y3U=" + }, + "convert-source-map": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.5.0.tgz", + "integrity": "sha1-ms1whRxtXf3ZPZKC5e35SgP/RrU=" + }, + "core-js": { + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/core-js/-/core-js-2.5.1.tgz", + "integrity": "sha1-rmh03GaTd4m4B1T/VCjfZoGcpQs=" + }, + "core-util-is": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz", + "integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=" + }, + "create-ecdh": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/create-ecdh/-/create-ecdh-4.0.0.tgz", + "integrity": "sha1-iIxyNZbN92EvZJgjPuvXo1MBc30=", + "requires": { + "bn.js": "4.11.8", + "elliptic": "6.4.0" + } + }, + "create-error-class": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/create-error-class/-/create-error-class-3.0.2.tgz", + "integrity": "sha1-Br56vvlHo/FKMP1hBnHUAbyot7Y=", + "requires": { + "capture-stack-trace": "1.0.0" + } + }, + "create-hash": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/create-hash/-/create-hash-1.1.3.tgz", + "integrity": "sha1-YGBCrIuSYnUPSDyt2rD1gZFy2P0=", + "requires": { + "cipher-base": "1.0.4", + "inherits": "2.0.3", + "ripemd160": "2.0.1", + "sha.js": "2.4.9" + } + }, + "create-hmac": { + "version": "1.1.6", + "resolved": "https://registry.npmjs.org/create-hmac/-/create-hmac-1.1.6.tgz", + "integrity": "sha1-rLniIaThe9sHbpBlfEK5PjcmzwY=", + "requires": { + "cipher-base": "1.0.4", + "create-hash": "1.1.3", + "inherits": "2.0.3", + "ripemd160": "2.0.1", + "safe-buffer": "5.1.1", + "sha.js": "2.4.9" + } + }, + "crypto-browserify": { + "version": "3.12.0", + "resolved": "https://registry.npmjs.org/crypto-browserify/-/crypto-browserify-3.12.0.tgz", + "integrity": "sha512-fz4spIh+znjO2VjL+IdhEpRJ3YN6sMzITSBijk6FK2UvTqruSQW+/cCZTSNsMiZNvUeq0CqurF+dAbyiGOY6Wg==", + "requires": { + "browserify-cipher": "1.0.0", + "browserify-sign": "4.0.4", + "create-ecdh": "4.0.0", + "create-hash": "1.1.3", + "create-hmac": "1.1.6", + "diffie-hellman": "5.0.2", + "inherits": "2.0.3", + "pbkdf2": "3.0.14", + "public-encrypt": "4.0.0", + "randombytes": "2.0.5", + "randomfill": "1.0.3" + } + }, + "date-now": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/date-now/-/date-now-0.1.4.tgz", + "integrity": "sha1-6vQ5/U1ISK105cx9vvIAZyueNFs=" + }, + "debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "requires": { + "ms": "2.0.0" + } + }, + "decamelize": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-1.2.0.tgz", + "integrity": "sha1-9lNNFRSCabIDUue+4m9QH5oZEpA=" + }, + "deep-extend": { + "version": "0.4.2", + "resolved": "https://registry.npmjs.org/deep-extend/-/deep-extend-0.4.2.tgz", + "integrity": "sha1-SLaZwn4zS/ifEIkr5DL25MfTSn8=" + }, + "define-properties": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.1.2.tgz", + "integrity": "sha1-g6c/L+pWmJj7c3GTyPhzyvbUXJQ=", + "requires": { + "foreach": "2.0.5", + "object-keys": "1.0.11" + } + }, + "defined": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/defined/-/defined-1.0.0.tgz", + "integrity": "sha1-yY2bzvdWdBiOEQlpFRGZ45sfppM=" + }, + "delegates": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/delegates/-/delegates-1.0.0.tgz", + "integrity": "sha1-hMbhWbgZBP3KWaDvRM2HDTElD5o=" + }, + "deps-sort": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/deps-sort/-/deps-sort-2.0.0.tgz", + "integrity": "sha1-CRckkC6EZYJg65EHSMzNGvbiH7U=", + "requires": { + "JSONStream": "1.3.1", + "shasum": "1.0.2", + "subarg": "1.0.0", + "through2": "2.0.3" + } + }, + "des.js": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/des.js/-/des.js-1.0.0.tgz", + "integrity": "sha1-wHTS4qpqipoH29YfmhXCzYPsjsw=", + "requires": { + "inherits": "2.0.3", + "minimalistic-assert": "1.0.0" + } + }, + "detect-browser": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/detect-browser/-/detect-browser-2.0.0.tgz", + "integrity": "sha512-vQjc6hQMz/GwfKM8U7BcdO3uZ+FACMz5YHx1C8LQvv59BgfzL6opXtl2qfosTJCbSvaRHUQc3xSEkXC6AHFAsQ==" + }, + "detect-indent": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/detect-indent/-/detect-indent-4.0.0.tgz", + "integrity": "sha1-920GQ1LN9Docts5hnE7jqUdd4gg=", + "requires": { + "repeating": "2.0.1" + } + }, + "detect-node": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/detect-node/-/detect-node-2.0.3.tgz", + "integrity": "sha1-ogM8CcyOFY03dI+951B4Mr1s4Sc=" + }, + "detective": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/detective/-/detective-4.5.0.tgz", + "integrity": "sha1-blqMaybmx6JUsca210kNmOyR7dE=", + "requires": { + "acorn": "4.0.13", + "defined": "1.0.0" + } + }, + "diff": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/diff/-/diff-3.2.0.tgz", + "integrity": "sha1-yc45Okt8vQsFinJck98pkCeGj/k=", + "dev": true + }, + "diffie-hellman": { + "version": "5.0.2", + "resolved": "https://registry.npmjs.org/diffie-hellman/-/diffie-hellman-5.0.2.tgz", + "integrity": "sha1-tYNXOScM/ias9jIJn97SoH8gnl4=", + "requires": { + "bn.js": "4.11.8", + "miller-rabin": "4.0.1", + "randombytes": "2.0.5" + } + }, + "dns-packet": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/dns-packet/-/dns-packet-1.2.2.tgz", + "integrity": "sha512-kN+DjfGF7dJGUL7nWRktL9Z18t1rWP3aQlyZdY8XlpvU3Nc6GeFTQApftcjtWKxAZfiggZSGrCEoszNgvnpwDg==", + "requires": { + "ip": "1.1.5", + "safe-buffer": "5.1.1" + } + }, + "dns-socket": { + "version": "1.6.2", + "resolved": "https://registry.npmjs.org/dns-socket/-/dns-socket-1.6.2.tgz", + "integrity": "sha512-Ztbaf5fToBfm/4+sVEJi7mT2mJOLYYpI+TpgOhxwp5l28UwunTpHMccVhTe9L0F6pQ2cUF0ja9ukuTCtzYq2Ig==", + "requires": { + "dns-packet": "1.2.2" + } + }, + "domain-browser": { + "version": "1.1.7", + "resolved": "https://registry.npmjs.org/domain-browser/-/domain-browser-1.1.7.tgz", + "integrity": "sha1-hnqksJP6oF8d4IwG9NeyH9+GmLw=" + }, + "drbg.js": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/drbg.js/-/drbg.js-1.0.1.tgz", + "integrity": "sha1-Pja2xCs3BDgjzbwzLVjzHiRFSAs=", + "requires": { + "browserify-aes": "1.1.1", + "create-hash": "1.1.3", + "create-hmac": "1.1.6" + } + }, + "duplexer2": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/duplexer2/-/duplexer2-0.1.4.tgz", + "integrity": "sha1-ixLauHjA1p4+eJEFFmKjL8a93ME=", + "requires": { + "readable-stream": "2.3.3" + } + }, + "duplexer3": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/duplexer3/-/duplexer3-0.1.4.tgz", + "integrity": "sha1-7gHdHKwO08vH/b6jfcCo8c4ALOI=" + }, + "elliptic": { + "version": "6.4.0", + "resolved": "https://registry.npmjs.org/elliptic/-/elliptic-6.4.0.tgz", + "integrity": "sha1-ysmvh2LIWDYYcAPI3+GT5eLq5d8=", + "requires": { + "bn.js": "4.11.8", + "brorand": "1.1.0", + "hash.js": "1.1.3", + "hmac-drbg": "1.0.1", + "inherits": "2.0.3", + "minimalistic-assert": "1.0.0", + "minimalistic-crypto-utils": "1.0.1" + } + }, + "end-of-stream": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.0.tgz", + "integrity": "sha1-epDYM+/abPpurA9JSduw+tOmMgY=", + "requires": { + "once": "1.4.0" + } + }, + "error-ex": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.1.tgz", + "integrity": "sha1-+FWobOYa3E6GIcPNoh56dhLDqNw=", + "requires": { + "is-arrayish": "0.2.1" + } + }, + "es-abstract": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.9.0.tgz", + "integrity": "sha512-kk3IJoKo7A3pWJc0OV8yZ/VEX2oSUytfekrJiqoxBlKJMFAJVJVpGdHClCCTdv+Fn2zHfpDHHIelMFhZVfef3Q==", + "requires": { + "es-to-primitive": "1.1.1", + "function-bind": "1.1.1", + "has": "1.0.1", + "is-callable": "1.1.3", + "is-regex": "1.0.4" + } + }, + "es-to-primitive": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/es-to-primitive/-/es-to-primitive-1.1.1.tgz", + "integrity": "sha1-RTVSSKiJeQNLZ5Lhm7gfK3l13Q0=", + "requires": { + "is-callable": "1.1.3", + "is-date-object": "1.0.1", + "is-symbol": "1.0.1" + } + }, + "escape-string-regexp": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", + "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=" + }, + "escodegen": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/escodegen/-/escodegen-1.3.3.tgz", + "integrity": "sha1-8CQBb1qI4Eb9EgBQVek5gC5sXyM=", + "requires": { + "esprima": "1.1.1", + "estraverse": "1.5.1", + "esutils": "1.0.0", + "source-map": "0.1.43" + }, + "dependencies": { + "esutils": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/esutils/-/esutils-1.0.0.tgz", + "integrity": "sha1-gVHTWOIMisx/t0XnRywAJf5JZXA=" + }, + "source-map": { + "version": "0.1.43", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.1.43.tgz", + "integrity": "sha1-wkvBRspRfBRx9drL4lcbK3+eM0Y=", + "optional": true, + "requires": { + "amdefine": "1.0.1" + } + } + } + }, + "esprima": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/esprima/-/esprima-1.1.1.tgz", + "integrity": "sha1-W28VR/TRAuZw4UDFCb5ncdautUk=" + }, + "estraverse": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-1.5.1.tgz", + "integrity": "sha1-hno+jlip+EYYr7bC3bzZFrfLr3E=" + }, + "esutils": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.2.tgz", + "integrity": "sha1-Cr9PHKpbyx96nYrMbepPqqBLrJs=" + }, + "events": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/events/-/events-1.1.1.tgz", + "integrity": "sha1-nr23Y1rQmccNzEwqH1AEKI6L2SQ=" + }, + "evp_bytestokey": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/evp_bytestokey/-/evp_bytestokey-1.0.3.tgz", + "integrity": "sha512-/f2Go4TognH/KvCISP7OUsHn85hT9nUkxxA9BEWxFn+Oj9o8ZNLm/40hdlgSLyuOimsrTKLUMEorQexp/aPQeA==", + "requires": { + "md5.js": "1.3.4", + "safe-buffer": "5.1.1" + } + }, + "expand-template": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/expand-template/-/expand-template-1.1.0.tgz", + "integrity": "sha512-kkjwkMqj0h4w/sb32ERCDxCQkREMCAgS39DscDnSwDsbxnwwM1BTZySdC3Bn1lhY7vL08n9GoO/fVTynjDgRyQ==" + }, + "expect": { + "version": "1.20.2", + "resolved": "https://registry.npmjs.org/expect/-/expect-1.20.2.tgz", + "integrity": "sha1-1Fj+TFYAQDa64yMkFqP2Nh8E+WU=", + "requires": { + "define-properties": "1.1.2", + "has": "1.0.1", + "is-equal": "1.5.5", + "is-regex": "1.0.4", + "object-inspect": "1.4.0", + "object-keys": "1.0.11", + "tmatch": "2.0.1" + }, + "dependencies": { + "object-inspect": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.4.0.tgz", + "integrity": "sha512-6QW38aBzieGzJqBaq0VBCgVMuluSYAHMH0xR1CMGfVU3mWLimWhkP97NGBLpJZXYDswaY+Qbo7ExFMTE0w/6zQ==" + } + } + }, + "falafel": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/falafel/-/falafel-2.1.0.tgz", + "integrity": "sha1-lrsXdh2rqU9G0AFzizzt86Z/4Gw=", + "requires": { + "acorn": "5.2.1", + "foreach": "2.0.5", + "isarray": "0.0.1", + "object-keys": "1.0.11" + }, + "dependencies": { + "acorn": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-5.2.1.tgz", + "integrity": "sha512-jG0u7c4Ly+3QkkW18V+NRDN+4bWHdln30NL1ZL2AvFZZmQe/BfopYCtghCKKVBUSetZ4QKcyA0pY6/4Gw8Pv8w==" + }, + "isarray": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz", + "integrity": "sha1-ihis/Kmo9Bd+Cav8YDiTmwXR7t8=" + } + } + }, + "file-saver": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/file-saver/-/file-saver-1.3.3.tgz", + "integrity": "sha1-zdTETTqiZOrC9o7BZbx5HDSvEjI=" + }, + "find-up": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-1.1.2.tgz", + "integrity": "sha1-ay6YIrGizgpgq2TWEOzK1TyyTQ8=", + "requires": { + "path-exists": "2.1.0", + "pinkie-promise": "2.0.1" + } + }, + "flatmap": { + "version": "0.0.3", + "resolved": "https://registry.npmjs.org/flatmap/-/flatmap-0.0.3.tgz", + "integrity": "sha1-Hxik2TgVLUlZZfnJWNkjqy3WabQ=" + }, + "foreach": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/foreach/-/foreach-2.0.5.tgz", + "integrity": "sha1-C+4AUBiusmDQo6865ljdATbsG5k=" + }, + "fs.realpath": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", + "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=" + }, + "fstat-mode": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/fstat-mode/-/fstat-mode-0.0.1.tgz", + "integrity": "sha1-1MEQBMAv+FhOBOUyM/nB7JuGJMo=" + }, + "function-bind": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", + "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==" + }, + "gauge": { + "version": "2.7.4", + "resolved": "https://registry.npmjs.org/gauge/-/gauge-2.7.4.tgz", + "integrity": "sha1-LANAXHU4w51+s3sxcCLjJfsBi/c=", + "requires": { + "aproba": "1.2.0", + "console-control-strings": "1.1.0", + "has-unicode": "2.0.1", + "object-assign": "4.1.1", + "signal-exit": "3.0.2", + "string-width": "1.0.2", + "strip-ansi": "3.0.1", + "wide-align": "1.1.2" + } + }, + "get-caller-file": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-1.0.2.tgz", + "integrity": "sha1-9wLmMSfn4jHBYKgMFVSstw1QR+U=" + }, + "get-stream": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-3.0.0.tgz", + "integrity": "sha1-jpQ9E1jcN1VQVOy+LtsFqhdO3hQ=" + }, + "github-from-package": { + "version": "0.0.0", + "resolved": "https://registry.npmjs.org/github-from-package/-/github-from-package-0.0.0.tgz", + "integrity": "sha1-l/tdlr/eiXMxPyDoKI75oWf6ZM4=" + }, + "glob": { + "version": "7.1.2", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.2.tgz", + "integrity": "sha512-MJTUg1kjuLeQCJ+ccE4Vpa6kKVXkPYJ2mOCQyUuKLcLQsdrMCpBPUi8qVE6+YuaJkozeA9NusTAw3hLr8Xe5EQ==", + "requires": { + "fs.realpath": "1.0.0", + "inflight": "1.0.6", + "inherits": "2.0.3", + "minimatch": "3.0.4", + "once": "1.4.0", + "path-is-absolute": "1.0.1" + } + }, + "glob-escape": { + "version": "0.0.2", + "resolved": "https://registry.npmjs.org/glob-escape/-/glob-escape-0.0.2.tgz", + "integrity": "sha1-nCf3gh7RwTd1gvPv2VWOP2dWKO0=" + }, + "globals": { + "version": "9.18.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-9.18.0.tgz", + "integrity": "sha512-S0nG3CLEQiY/ILxqtztTWH/3iRRdyBLw6KMDxnKMchrtbj2OFmehVh0WUCfW3DUrIgx/qFrJPICrq4Z4sTR9UQ==" + }, + "got": { + "version": "6.7.1", + "resolved": "https://registry.npmjs.org/got/-/got-6.7.1.tgz", + "integrity": "sha1-JAzQV4WpoY5WHcG0S0HHY+8ejbA=", + "requires": { + "create-error-class": "3.0.2", + "duplexer3": "0.1.4", + "get-stream": "3.0.0", + "is-redirect": "1.0.0", + "is-retry-allowed": "1.1.0", + "is-stream": "1.1.0", + "lowercase-keys": "1.0.0", + "safe-buffer": "5.1.1", + "timed-out": "4.0.1", + "unzip-response": "2.0.1", + "url-parse-lax": "1.0.0" + }, + "dependencies": { + "unzip-response": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/unzip-response/-/unzip-response-2.0.1.tgz", + "integrity": "sha1-0vD3N9FrBhXnKmk17QQhRXLVb5c=" + } + } + }, + "graceful-fs": { + "version": "4.1.11", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.1.11.tgz", + "integrity": "sha1-Dovf5NHduIVNZOBOp8AOKgJuVlg=" + }, + "graceful-readlink": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/graceful-readlink/-/graceful-readlink-1.0.1.tgz", + "integrity": "sha1-TK+tdrxi8C+gObL5Tpo906ORpyU=", + "dev": true + }, + "growl": { + "version": "1.9.2", + "resolved": "https://registry.npmjs.org/growl/-/growl-1.9.2.tgz", + "integrity": "sha1-Dqd0NxXbjY3ixe3hd14bRayFwC8=", + "dev": true + }, + "has": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/has/-/has-1.0.1.tgz", + "integrity": "sha1-hGFzP1OLCDfJNh45qauelwTcLyg=", + "requires": { + "function-bind": "1.1.1" + } + }, + "has-ansi": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/has-ansi/-/has-ansi-2.0.0.tgz", + "integrity": "sha1-NPUEnOHs3ysGSa8+8k5F7TVBbZE=", + "requires": { + "ansi-regex": "2.1.1" + } + }, + "has-flag": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-1.0.0.tgz", + "integrity": "sha1-nZ55MWXOAXoA8AQYxD+UKnsdEfo=", + "dev": true + }, + "has-unicode": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/has-unicode/-/has-unicode-2.0.1.tgz", + "integrity": "sha1-4Ob+aijPUROIVeCG0Wkedx3iqLk=" + }, + "hash-base": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/hash-base/-/hash-base-2.0.2.tgz", + "integrity": "sha1-ZuodhW206KVHDK32/OI65SRO8uE=", + "requires": { + "inherits": "2.0.3" + } + }, + "hash.js": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/hash.js/-/hash.js-1.1.3.tgz", + "integrity": "sha512-/UETyP0W22QILqS+6HowevwhEFJ3MBJnwTf75Qob9Wz9t0DPuisL8kW8YZMK62dHAKE1c1p+gY1TtOLY+USEHA==", + "requires": { + "inherits": "2.0.3", + "minimalistic-assert": "1.0.0" + } + }, + "he": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/he/-/he-1.1.1.tgz", + "integrity": "sha1-k0EP0hsAlzUVH4howvJx80J+I/0=" + }, + "hmac-drbg": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/hmac-drbg/-/hmac-drbg-1.0.1.tgz", + "integrity": "sha1-0nRXAQJabHdabFRXk+1QL8DGSaE=", + "requires": { + "hash.js": "1.1.3", + "minimalistic-assert": "1.0.0", + "minimalistic-crypto-utils": "1.0.1" + } + }, + "home-or-tmp": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/home-or-tmp/-/home-or-tmp-2.0.0.tgz", + "integrity": "sha1-42w/LSyufXRqhX440Y1fMqeILbg=", + "requires": { + "os-homedir": "1.0.2", + "os-tmpdir": "1.0.2" + } + }, + "hosted-git-info": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.5.0.tgz", + "integrity": "sha512-pNgbURSuab90KbTqvRPsseaTxOJCZBD0a7t+haSN33piP9cCM4l0CqdzAif2hUqm716UovKB2ROmiabGAKVXyg==" + }, + "htmlescape": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/htmlescape/-/htmlescape-1.1.1.tgz", + "integrity": "sha1-OgPtwiFLyjtmQko+eVk0lQnLA1E=" + }, + "https-browserify": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/https-browserify/-/https-browserify-1.0.0.tgz", + "integrity": "sha1-7AbBDgo0wPL68Zn3/X/Hj//QPHM=" + }, + "ieee754": { + "version": "1.1.8", + "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.1.8.tgz", + "integrity": "sha1-vjPUCsEO8ZJnAfbwii2G+/0a0+Q=" + }, + "indent-string": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/indent-string/-/indent-string-3.2.0.tgz", + "integrity": "sha1-Sl/W0nzDMvN+VBmlBNu4NxBckok=" + }, + "indexof": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/indexof/-/indexof-0.0.1.tgz", + "integrity": "sha1-gtwzbSMrkGIXnQWrMpOmYFn9Q10=" + }, + "inflight": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", + "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=", + "requires": { + "once": "1.4.0", + "wrappy": "1.0.2" + } + }, + "inherits": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", + "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=" + }, + "ini": { + "version": "1.3.4", + "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.4.tgz", + "integrity": "sha1-BTfLedr1m1mhpRff9wbIbsA5Fi4=" + }, + "inline-source-map": { + "version": "0.6.2", + "resolved": "https://registry.npmjs.org/inline-source-map/-/inline-source-map-0.6.2.tgz", + "integrity": "sha1-+Tk0ccGKedFyT4Y/o4tYY3Ct4qU=", + "requires": { + "source-map": "0.5.7" + } + }, + "insert-module-globals": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/insert-module-globals/-/insert-module-globals-7.0.1.tgz", + "integrity": "sha1-wDv04BywhtW15azorQr+eInWOMM=", + "requires": { + "JSONStream": "1.3.1", + "combine-source-map": "0.7.2", + "concat-stream": "1.5.2", + "is-buffer": "1.1.6", + "lexical-scope": "1.2.0", + "process": "0.11.10", + "through2": "2.0.3", + "xtend": "4.0.1" + } + }, + "install": { + "version": "0.10.1", + "resolved": "https://registry.npmjs.org/install/-/install-0.10.1.tgz", + "integrity": "sha1-HHtTyN1zNe9TTCZI3ij1md8b3Zc=" + }, + "invariant": { + "version": "2.2.2", + "resolved": "https://registry.npmjs.org/invariant/-/invariant-2.2.2.tgz", + "integrity": "sha1-nh9WrArNtr8wMwbzOL47IErmA2A=", + "requires": { + "loose-envify": "1.3.1" + } + }, + "invert-kv": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/invert-kv/-/invert-kv-1.0.0.tgz", + "integrity": "sha1-EEqOSqym09jNFXqO+L+rLXo//bY=" + }, + "ip": { + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/ip/-/ip-1.1.5.tgz", + "integrity": "sha1-vd7XARQpCCjAoDnnLvJfWq7ENUo=" + }, + "ip-regex": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/ip-regex/-/ip-regex-2.1.0.tgz", + "integrity": "sha1-+ni/XS5pE8kRzp+BnuUUa7bYROk=" + }, + "ipfs-api": { + "version": "14.3.7", + "resolved": "https://registry.npmjs.org/ipfs-api/-/ipfs-api-14.3.7.tgz", + "integrity": "sha512-SeCKT6KwMuu/qDEMDd5CRj2KhSa1+Dyx63jJgadU2tD6QINyxCy/ooPFBhZRwlGuAhb61IVSV8pfZ0nHNQEINQ==", + "requires": { + "async": "2.6.0", + "bs58": "4.0.1", + "cids": "0.5.2", + "concat-stream": "1.6.0", + "detect-node": "2.0.3", + "flatmap": "0.0.3", + "glob": "7.1.2", + "glob-escape": "0.0.2", + "ipfs-block": "0.6.1", + "ipfs-unixfs": "0.1.14", + "ipld-dag-pb": "0.11.3", + "is-ipfs": "0.3.2", + "is-stream": "1.1.0", + "lru-cache": "4.1.1", + "multiaddr": "3.0.1", + "multihashes": "0.4.12", + "multipart-stream": "2.0.1", + "ndjson": "1.5.0", + "once": "1.4.0", + "peer-id": "0.10.2", + "peer-info": "0.11.1", + "promisify-es6": "1.0.3", + "pump": "1.0.2", + "qs": "6.5.1", + "readable-stream": "2.3.3", + "stream-http": "2.7.2", + "streamifier": "0.1.1", + "tar-stream": "1.5.5" + }, + "dependencies": { + "concat-stream": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/concat-stream/-/concat-stream-1.6.0.tgz", + "integrity": "sha1-CqxmL9Ur54lk1VMvaUeE5wEQrPc=", + "requires": { + "inherits": "2.0.3", + "readable-stream": "2.3.3", + "typedarray": "0.0.6" + } + } + } + }, + "ipfs-block": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/ipfs-block/-/ipfs-block-0.6.1.tgz", + "integrity": "sha512-28dgGsb2YsYnFs+To4cVBX8e/lTCb8eWDzGhN5csj3a/sHMOYrHeK8+Ez0IV67CI3lqKGuG/ZD01Cmd6JUvKrQ==", + "requires": { + "cids": "0.5.2" + } + }, + "ipfs-unixfs": { + "version": "0.1.14", + "resolved": "https://registry.npmjs.org/ipfs-unixfs/-/ipfs-unixfs-0.1.14.tgz", + "integrity": "sha512-s1tEnwKhdd17MmyC/EUMNVMDYzKhCiHDI11TF8tSBeWkEQp+0WUxkYuqvz0R5TSi2lNDJ/oVnEmwWhki2spUiQ==", + "requires": { + "protons": "1.0.0" + } + }, + "ipld-dag-pb": { + "version": "0.11.3", + "resolved": "https://registry.npmjs.org/ipld-dag-pb/-/ipld-dag-pb-0.11.3.tgz", + "integrity": "sha512-EVu9hxlvvZQyEmV27vokBJbi3EgAJZYPYAbEvutcW3gQidADlgRx8R7WJ6+w/aL80H6ZyMuzR/8JT91YsoZNeA==", + "requires": { + "async": "2.6.0", + "bs58": "4.0.1", + "buffer-loader": "0.0.1", + "cids": "0.5.2", + "ipfs-block": "0.6.1", + "is-ipfs": "0.3.2", + "multihashes": "0.4.12", + "multihashing-async": "0.4.7", + "protons": "1.0.0", + "pull-stream": "3.6.1", + "pull-traverse": "1.0.3", + "stable": "0.1.6" + } + }, + "is-arrayish": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz", + "integrity": "sha1-d8mYQFJ6qOyxqLppe4BkWnqSap0=" + }, + "is-arrow-function": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/is-arrow-function/-/is-arrow-function-2.0.3.tgz", + "integrity": "sha1-Kb4sLY2UUIUri7r7Y1unuNjofsI=", + "requires": { + "is-callable": "1.1.3" + } + }, + "is-boolean-object": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-boolean-object/-/is-boolean-object-1.0.0.tgz", + "integrity": "sha1-mPiygDBoQhmpXzdc+9iM40Bd/5M=" + }, + "is-buffer": { + "version": "1.1.6", + "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.6.tgz", + "integrity": "sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w==" + }, + "is-builtin-module": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-builtin-module/-/is-builtin-module-1.0.0.tgz", + "integrity": "sha1-VAVy0096wxGfj3bDDLwbHgN6/74=", + "requires": { + "builtin-modules": "1.1.1" + } + }, + "is-callable": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.1.3.tgz", + "integrity": "sha1-hut1OSgF3cM69xySoO7fdO52BLI=" + }, + "is-date-object": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-date-object/-/is-date-object-1.0.1.tgz", + "integrity": "sha1-mqIOtq7rv/d/vTPnTKAbM1gdOhY=" + }, + "is-equal": { + "version": "1.5.5", + "resolved": "https://registry.npmjs.org/is-equal/-/is-equal-1.5.5.tgz", + "integrity": "sha1-XoXxlX4FKIMkf+s4aWWju6Ffuz0=", + "requires": { + "has": "1.0.1", + "is-arrow-function": "2.0.3", + "is-boolean-object": "1.0.0", + "is-callable": "1.1.3", + "is-date-object": "1.0.1", + "is-generator-function": "1.0.6", + "is-number-object": "1.0.3", + "is-regex": "1.0.4", + "is-string": "1.0.4", + "is-symbol": "1.0.1", + "object.entries": "1.0.4" + } + }, + "is-finite": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-finite/-/is-finite-1.0.2.tgz", + "integrity": "sha1-zGZ3aVYCvlUO8R6LSqYwU0K20Ko=", + "requires": { + "number-is-nan": "1.0.1" + } + }, + "is-fullwidth-code-point": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz", + "integrity": "sha1-754xOG8DGn8NZDr4L95QxFfvAMs=", + "requires": { + "number-is-nan": "1.0.1" + } + }, + "is-generator-function": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/is-generator-function/-/is-generator-function-1.0.6.tgz", + "integrity": "sha1-nnFlPNFf/zQcecQVFGChMdMen8Q=" + }, + "is-ip": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-ip/-/is-ip-2.0.0.tgz", + "integrity": "sha1-aO6gfooKCpTC0IDdZ0xzGrKkYas=", + "requires": { + "ip-regex": "2.1.0" + } + }, + "is-ipfs": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/is-ipfs/-/is-ipfs-0.3.2.tgz", + "integrity": "sha512-82V1j4LMkYy7H4seQQzOWqo7FiW3I64/1/ryo3dhtWKfOvm7ZolLMRQQfGKs4OXWauh5rAkPnamVcRISHwhmpQ==", + "requires": { + "bs58": "4.0.1", + "cids": "0.5.2", + "multihashes": "0.4.12" + } + }, + "is-number-object": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/is-number-object/-/is-number-object-1.0.3.tgz", + "integrity": "sha1-8mWrian0RQNO9q/xWo8AsA9VF5k=" + }, + "is-online": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/is-online/-/is-online-7.0.0.tgz", + "integrity": "sha1-fiQIwK4efje6jVC9sjcmDTK/2W4=", + "requires": { + "got": "6.7.1", + "p-any": "1.1.0", + "p-timeout": "1.2.0", + "public-ip": "2.3.5" + } + }, + "is-promise": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-promise/-/is-promise-1.0.1.tgz", + "integrity": "sha1-MVc3YcBX4zwukaq56W2gjO++duU=" + }, + "is-redirect": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-redirect/-/is-redirect-1.0.0.tgz", + "integrity": "sha1-HQPd7VO9jbDzDCbk+V02/HyH3CQ=" + }, + "is-regex": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.0.4.tgz", + "integrity": "sha1-VRdIm1RwkbCTDglWVM7SXul+lJE=", + "requires": { + "has": "1.0.1" + } + }, + "is-retry-allowed": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/is-retry-allowed/-/is-retry-allowed-1.1.0.tgz", + "integrity": "sha1-EaBgVotnM5REAz0BJaYaINVk+zQ=" + }, + "is-stream": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-1.1.0.tgz", + "integrity": "sha1-EtSj3U5o4Lec6428hBc66A2RykQ=" + }, + "is-string": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/is-string/-/is-string-1.0.4.tgz", + "integrity": "sha1-zDqbaYV9Yh6WNyWiTK7shzuCbmQ=" + }, + "is-symbol": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-symbol/-/is-symbol-1.0.1.tgz", + "integrity": "sha1-PMWfAAJRlLarLjjbrmaJJWtmBXI=" + }, + "is-utf8": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/is-utf8/-/is-utf8-0.2.1.tgz", + "integrity": "sha1-Sw2hRCEE0bM2NA6AeX6GXPOffXI=" + }, + "isarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", + "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=" + }, + "js-sha3": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/js-sha3/-/js-sha3-0.6.1.tgz", + "integrity": "sha1-W4n3enR3Z5h39YxKB1JAk0sflcA=" + }, + "js-tokens": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-3.0.2.tgz", + "integrity": "sha1-mGbfOVECEw449/mWvOtlRDIJwls=" + }, + "jsesc": { + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-0.5.0.tgz", + "integrity": "sha1-597mbjXW/Bb3EP6R1c9p9w8IkR0=" + }, + "json-stable-stringify": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/json-stable-stringify/-/json-stable-stringify-0.0.1.tgz", + "integrity": "sha1-YRwj6BTbN1Un34URk9tZ3Sryf0U=", + "requires": { + "jsonify": "0.0.0" + } + }, + "json-stringify-safe": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz", + "integrity": "sha1-Epai1Y/UXxmg9s4B1lcB4sc1tus=" + }, + "json3": { + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/json3/-/json3-3.3.2.tgz", + "integrity": "sha1-PAQ0dD35Pi9cQq7nsZvLSDV19OE=", + "dev": true + }, + "json5": { + "version": "0.5.1", + "resolved": "https://registry.npmjs.org/json5/-/json5-0.5.1.tgz", + "integrity": "sha1-Hq3nrMASA0rYTiOWdn6tn6VJWCE=" + }, + "jsonify": { + "version": "0.0.0", + "resolved": "https://registry.npmjs.org/jsonify/-/jsonify-0.0.0.tgz", + "integrity": "sha1-LHS27kHZPKUbe1qu6PUDYx0lKnM=" + }, + "jsonparse": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/jsonparse/-/jsonparse-1.3.1.tgz", + "integrity": "sha1-P02uSpH6wxX3EGL4UhzCOfE2YoA=" + }, + "keypair": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/keypair/-/keypair-1.0.1.tgz", + "integrity": "sha1-dgNxknCvtlZO04oiCHoG/Jqk6hs=" + }, + "labeled-stream-splicer": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/labeled-stream-splicer/-/labeled-stream-splicer-2.0.0.tgz", + "integrity": "sha1-pS4dE4AkwAuGscDJH2d5GLiuClk=", + "requires": { + "inherits": "2.0.3", + "isarray": "0.0.1", + "stream-splicer": "2.0.0" + }, + "dependencies": { + "isarray": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz", + "integrity": "sha1-ihis/Kmo9Bd+Cav8YDiTmwXR7t8=" + } + } + }, + "lcid": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/lcid/-/lcid-1.0.0.tgz", + "integrity": "sha1-MIrMr6C8SDo4Z7S28rlQYlHRuDU=", + "requires": { + "invert-kv": "1.0.0" + } + }, + "lexical-scope": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/lexical-scope/-/lexical-scope-1.2.0.tgz", + "integrity": "sha1-/Ope3HBKSzqHls3KQZw6CvryLfQ=", + "requires": { + "astw": "2.2.0" + } + }, + "libp2p-crypto": { + "version": "0.10.3", + "resolved": "https://registry.npmjs.org/libp2p-crypto/-/libp2p-crypto-0.10.3.tgz", + "integrity": "sha512-E03YpbwOOQzEunR0OpWtuU8LPcBJnVZEfwCsVP17ngLH5pMhzIy3t9imEOkMT6vLnsxe25Q/HIiipNgRDxyd5g==", + "requires": { + "asn1.js": "4.9.2", + "async": "2.6.0", + "browserify-aes": "1.1.1", + "keypair": "1.0.1", + "libp2p-crypto-secp256k1": "0.2.2", + "multihashing-async": "0.4.7", + "pem-jwk": "1.5.1", + "protons": "1.0.0", + "rsa-pem-to-jwk": "1.1.3", + "tweetnacl": "1.0.0", + "webcrypto-shim": "github:dignifiedquire/webcrypto-shim#190bc9ec341375df6025b17ae12ddb2428ea49c8" + } + }, + "libp2p-crypto-secp256k1": { + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/libp2p-crypto-secp256k1/-/libp2p-crypto-secp256k1-0.2.2.tgz", + "integrity": "sha1-DdUh8Yq8TjahUuJOmzYwewrpzwU=", + "requires": { + "async": "2.6.0", + "multihashing-async": "0.4.7", + "nodeify": "1.0.1", + "safe-buffer": "5.1.1", + "secp256k1": "3.3.1" + } + }, + "load-json-file": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/load-json-file/-/load-json-file-1.1.0.tgz", + "integrity": "sha1-lWkFcI1YtLq0wiYbBPWfMcmTdMA=", + "requires": { + "graceful-fs": "4.1.11", + "parse-json": "2.2.0", + "pify": "2.3.0", + "pinkie-promise": "2.0.1", + "strip-bom": "2.0.0" + } + }, + "lodash": { + "version": "4.17.4", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.4.tgz", + "integrity": "sha1-eCA6TRwyiuHYbcpkYONptX9AVa4=" + }, + "lodash._baseassign": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/lodash._baseassign/-/lodash._baseassign-3.2.0.tgz", + "integrity": "sha1-jDigmVAPIVrQnlnxci/QxSv+Ck4=", + "dev": true, + "requires": { + "lodash._basecopy": "3.0.1", + "lodash.keys": "3.1.2" + } + }, + "lodash._basecopy": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/lodash._basecopy/-/lodash._basecopy-3.0.1.tgz", + "integrity": "sha1-jaDmqHbPNEwK2KVIghEd08XHyjY=", + "dev": true + }, + "lodash._basecreate": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/lodash._basecreate/-/lodash._basecreate-3.0.3.tgz", + "integrity": "sha1-G8ZhYU2qf8MRt9A78WgGoCE8+CE=", + "dev": true + }, + "lodash._getnative": { + "version": "3.9.1", + "resolved": "https://registry.npmjs.org/lodash._getnative/-/lodash._getnative-3.9.1.tgz", + "integrity": "sha1-VwvH3t5G1hzc3mh9ZdPuy6o6r/U=", + "dev": true + }, + "lodash._isiterateecall": { + "version": "3.0.9", + "resolved": "https://registry.npmjs.org/lodash._isiterateecall/-/lodash._isiterateecall-3.0.9.tgz", + "integrity": "sha1-UgOte6Ql+uhCRg5pbbnPPmqsBXw=", + "dev": true + }, + "lodash.create": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/lodash.create/-/lodash.create-3.1.1.tgz", + "integrity": "sha1-1/KEnw29p+BGgruM1yqwIkYd6+c=", + "dev": true, + "requires": { + "lodash._baseassign": "3.2.0", + "lodash._basecreate": "3.0.3", + "lodash._isiterateecall": "3.0.9" + } + }, + "lodash.filter": { + "version": "4.6.0", + "resolved": "https://registry.npmjs.org/lodash.filter/-/lodash.filter-4.6.0.tgz", + "integrity": "sha1-ZosdSYFgOuHMWm+nYBQ+SAtMSs4=" + }, + "lodash.isarguments": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/lodash.isarguments/-/lodash.isarguments-3.1.0.tgz", + "integrity": "sha1-L1c9hcaiQon/AGY7SRwdM4/zRYo=", + "dev": true + }, + "lodash.isarray": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/lodash.isarray/-/lodash.isarray-3.0.4.tgz", + "integrity": "sha1-eeTriMNqgSKvhvhEqpvNhRtfu1U=", + "dev": true + }, + "lodash.keys": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/lodash.keys/-/lodash.keys-3.1.2.tgz", + "integrity": "sha1-TbwEcrFWvlCgsoaFXRvQsMZWCYo=", + "dev": true, + "requires": { + "lodash._getnative": "3.9.1", + "lodash.isarguments": "3.1.0", + "lodash.isarray": "3.0.4" + } + }, + "lodash.map": { + "version": "4.6.0", + "resolved": "https://registry.npmjs.org/lodash.map/-/lodash.map-4.6.0.tgz", + "integrity": "sha1-dx7Hg540c9nEzeKLGTlMNWL09tM=" + }, + "lodash.memoize": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/lodash.memoize/-/lodash.memoize-3.0.4.tgz", + "integrity": "sha1-LcvSwofLwKVcxCMovQxzYVDVPj8=" + }, + "lodash.uniqby": { + "version": "4.7.0", + "resolved": "https://registry.npmjs.org/lodash.uniqby/-/lodash.uniqby-4.7.0.tgz", + "integrity": "sha1-2ZwHpmnp5tJOE2Lf4mbGdhavEwI=" + }, + "loose-envify": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.3.1.tgz", + "integrity": "sha1-0aitM/qc4OcT1l/dCsi3SNR4yEg=", + "requires": { + "js-tokens": "3.0.2" + } + }, + "lowercase-keys": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/lowercase-keys/-/lowercase-keys-1.0.0.tgz", + "integrity": "sha1-TjNms55/VFfjXxMkvfb4jQv8cwY=" + }, + "lru-cache": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-4.1.1.tgz", + "integrity": "sha512-q4spe4KTfsAS1SUHLO0wz8Qiyf1+vMIAgpRYioFYDMNqKfHQbg+AVDH3i4fvpl71/P1L0dBl+fQi+P37UYf0ew==", + "requires": { + "pseudomap": "1.0.2", + "yallist": "2.1.2" + } + }, + "md5.js": { + "version": "1.3.4", + "resolved": "https://registry.npmjs.org/md5.js/-/md5.js-1.3.4.tgz", + "integrity": "sha1-6b296UogpawYsENA/Fdk1bCdkB0=", + "requires": { + "hash-base": "3.0.4", + "inherits": "2.0.3" + }, + "dependencies": { + "hash-base": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/hash-base/-/hash-base-3.0.4.tgz", + "integrity": "sha1-X8hoaEfs1zSZQDMZprCj8/auSRg=", + "requires": { + "inherits": "2.0.3", + "safe-buffer": "5.1.1" + } + } + } + }, + "miller-rabin": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/miller-rabin/-/miller-rabin-4.0.1.tgz", + "integrity": "sha512-115fLhvZVqWwHPbClyntxEVfVDfl9DLLTuJvq3g2O/Oxi8AiNouAHvDSzHS0viUJc+V5vm3eq91Xwqn9dp4jRA==", + "requires": { + "bn.js": "4.11.8", + "brorand": "1.1.0" + } + }, + "milligram": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/milligram/-/milligram-1.3.0.tgz", + "integrity": "sha1-pdmA746veTN8lqjXx+F2dkkxBCw=", + "requires": { + "normalize.css": "5.0.0" + }, + "dependencies": { + "normalize.css": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/normalize.css/-/normalize.css-5.0.0.tgz", + "integrity": "sha1-fOyHXOgXilMzxN6Ato6pwYudfDc=" + } + } + }, + "minimalistic-assert": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/minimalistic-assert/-/minimalistic-assert-1.0.0.tgz", + "integrity": "sha1-cCvi3aazf0g2vLP121ZkG2Sh09M=" + }, + "minimalistic-crypto-utils": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/minimalistic-crypto-utils/-/minimalistic-crypto-utils-1.0.1.tgz", + "integrity": "sha1-9sAMHAsIIkblxNmd+4x8CDsrWCo=" + }, + "minimatch": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", + "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==", + "requires": { + "brace-expansion": "1.1.8" + } + }, + "minimist": { + "version": "0.0.8", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-0.0.8.tgz", + "integrity": "sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0=" + }, + "mkdirp": { + "version": "0.5.1", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.1.tgz", + "integrity": "sha1-MAV0OOrGz3+MR2fzhkjWaX11yQM=", + "requires": { + "minimist": "0.0.8" + } + }, + "mocha": { + "version": "3.5.3", + "resolved": "https://registry.npmjs.org/mocha/-/mocha-3.5.3.tgz", + "integrity": "sha512-/6na001MJWEtYxHOV1WLfsmR4YIynkUEhBwzsb+fk2qmQ3iqsi258l/Q2MWHJMImAcNpZ8DEdYAK72NHoIQ9Eg==", + "dev": true, + "requires": { + "browser-stdout": "1.3.0", + "commander": "2.9.0", + "debug": "2.6.8", + "diff": "3.2.0", + "escape-string-regexp": "1.0.5", + "glob": "7.1.1", + "growl": "1.9.2", + "he": "1.1.1", + "json3": "3.3.2", + "lodash.create": "3.1.1", + "mkdirp": "0.5.1", + "supports-color": "3.1.2" + }, + "dependencies": { + "debug": { + "version": "2.6.8", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.8.tgz", + "integrity": "sha1-5zFTHKLt4n0YgiJCfaF4IdaP9Pw=", + "dev": true, + "requires": { + "ms": "2.0.0" + } + }, + "glob": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.1.tgz", + "integrity": "sha1-gFIR3wT6rxxjo2ADBs31reULLsg=", + "dev": true, + "requires": { + "fs.realpath": "1.0.0", + "inflight": "1.0.6", + "inherits": "2.0.3", + "minimatch": "3.0.4", + "once": "1.4.0", + "path-is-absolute": "1.0.1" + } + }, + "supports-color": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-3.1.2.tgz", + "integrity": "sha1-cqJiiU2dQIuVbKBf83su2KbiotU=", + "dev": true, + "requires": { + "has-flag": "1.0.0" + } + } + } + }, + "module-deps": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/module-deps/-/module-deps-4.1.1.tgz", + "integrity": "sha1-IyFYM/HaE/1gbMuAh7RIUty4If0=", + "requires": { + "JSONStream": "1.3.1", + "browser-resolve": "1.11.2", + "cached-path-relative": "1.0.1", + "concat-stream": "1.5.2", + "defined": "1.0.0", + "detective": "4.5.0", + "duplexer2": "0.1.4", + "inherits": "2.0.3", + "parents": "1.0.1", + "readable-stream": "2.3.3", + "resolve": "1.5.0", + "stream-combiner2": "1.1.1", + "subarg": "1.0.0", + "through2": "2.0.3", + "xtend": "4.0.1" + } + }, + "ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=" + }, + "multiaddr": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/multiaddr/-/multiaddr-3.0.1.tgz", + "integrity": "sha512-MnEf7gozRpX+x5sVl38lwv59YX9/HBojJuunINH+ko1/k11RMe3igA2oAOea1wVDltD5xkDnsoVxWnFiRxsScw==", + "requires": { + "bs58": "4.0.1", + "ip": "1.1.5", + "lodash.filter": "4.6.0", + "lodash.map": "4.6.0", + "varint": "5.0.0", + "xtend": "4.0.1" + } + }, + "multibase": { + "version": "0.3.4", + "resolved": "https://registry.npmjs.org/multibase/-/multibase-0.3.4.tgz", + "integrity": "sha1-+6iwqslyT2LiR4JVfioGLjDTrn8=", + "requires": { + "base-x": "3.0.0" + }, + "dependencies": { + "base-x": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/base-x/-/base-x-3.0.0.tgz", + "integrity": "sha1-d7VvAxEHC3gLPIpfU0vqxH5QZwI=" + } + } + }, + "multicodec": { + "version": "0.2.5", + "resolved": "https://registry.npmjs.org/multicodec/-/multicodec-0.2.5.tgz", + "integrity": "sha512-83MVRQi0j6cgYP0lqC+7HHbYKYpd074qy94OuzX/elmN8CTMF0/aH0Khb0pcRtALjD2ZFG3lgEy3bhwpCreO1g==", + "requires": { + "varint": "5.0.0" + } + }, + "multihashes": { + "version": "0.4.12", + "resolved": "https://registry.npmjs.org/multihashes/-/multihashes-0.4.12.tgz", + "integrity": "sha512-NU9bw9v9Lk1yd25qv4/c9Ks5ru85F3U0XBGmgooXX+BHVnHWyhgCZS0fsq0a2Jqjj2hqpT1AKjWw+og0e+OrpQ==", + "requires": { + "bs58": "4.0.1", + "varint": "5.0.0" + } + }, + "multihashing-async": { + "version": "0.4.7", + "resolved": "https://registry.npmjs.org/multihashing-async/-/multihashing-async-0.4.7.tgz", + "integrity": "sha512-jjW5r2M3zS7YZmylUH1FmrckD6pQXMeMQTAvTJyo83hfTZ3B6fyph7AvHaDdr3M6c4zlmvSCM8jpEItjJ9dxuw==", + "requires": { + "async": "2.6.0", + "blakejs": "1.1.0", + "js-sha3": "0.6.1", + "multihashes": "0.4.12", + "murmurhash3js": "3.0.1", + "nodeify": "1.0.1" + } + }, + "multipart-stream": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/multipart-stream/-/multipart-stream-2.0.1.tgz", + "integrity": "sha1-GVyctLLEHnjHKh6POMfQ66HNC6A=", + "requires": { + "inherits": "2.0.3", + "is-stream": "1.1.0", + "sandwich-stream": "1.0.0" + } + }, + "murmurhash3js": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/murmurhash3js/-/murmurhash3js-3.0.1.tgz", + "integrity": "sha1-Ppg+W0fCoG9DpxMXTn5DXKBEuZg=" + }, + "nan": { + "version": "2.7.0", + "resolved": "https://registry.npmjs.org/nan/-/nan-2.7.0.tgz", + "integrity": "sha1-2Vv3IeyHfgjbJ27T/G63j5CDrUY=" + }, + "ndjson": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/ndjson/-/ndjson-1.5.0.tgz", + "integrity": "sha1-rmA7NrE0vOw0e0UkIrC/mNWDLsg=", + "requires": { + "json-stringify-safe": "5.0.1", + "minimist": "1.2.0", + "split2": "2.2.0", + "through2": "2.0.3" + }, + "dependencies": { + "minimist": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz", + "integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ=" + } + } + }, + "node-abi": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/node-abi/-/node-abi-2.1.2.tgz", + "integrity": "sha512-hmUtb8m75RSi7N+zZLYqe75XDvZB+6LyTBPkj2DConvNgQet2e3BIqEwe1LLvqMrfyjabuT5ZOrTioLCH1HTdA==", + "requires": { + "semver": "5.4.1" + } + }, + "node-dir": { + "version": "0.1.17", + "resolved": "https://registry.npmjs.org/node-dir/-/node-dir-0.1.17.tgz", + "integrity": "sha1-X1Zl2TNRM1yqvvjxxVRRbPXx5OU=", + "requires": { + "minimatch": "3.0.4" + } + }, + "node-webcrypto-ossl": { + "version": "1.0.31", + "resolved": "https://registry.npmjs.org/node-webcrypto-ossl/-/node-webcrypto-ossl-1.0.31.tgz", + "integrity": "sha512-IrNfBY6ur0g0jtELGE0FqZ9/P9aPphDF/l/1Of//eFlwyYCjhsIKgHzyMbArixYeMRkGkHHWVpo+Ff1xc0dsRw==", + "requires": { + "mkdirp": "0.5.1", + "nan": "2.7.0", + "tslib": "1.8.0", + "webcrypto-core": "0.1.17" + } + }, + "nodeify": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/nodeify/-/nodeify-1.0.1.tgz", + "integrity": "sha1-ZKtpp7268DzhB7TwM1yHwLnpGx0=", + "requires": { + "is-promise": "1.0.1", + "promise": "1.3.0" + } + }, + "noop-logger": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/noop-logger/-/noop-logger-0.1.1.tgz", + "integrity": "sha1-lKKxYzxPExdVMAfYlm/Q6EG2pMI=" + }, + "normalize-package-data": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-2.4.0.tgz", + "integrity": "sha512-9jjUFbTPfEy3R/ad/2oNbKtW9Hgovl5O1FvFWKkKblNXoN/Oou6+9+KKohPK13Yc3/TyunyWhJp6gvRNR/PPAw==", + "requires": { + "hosted-git-info": "2.5.0", + "is-builtin-module": "1.0.0", + "semver": "5.4.1", + "validate-npm-package-license": "3.0.1" + } + }, + "normalize.css": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/normalize.css/-/normalize.css-7.0.0.tgz", + "integrity": "sha1-q/sd2CRwZ04DIrU86xqvQSk45L8=" + }, + "npm": { + "version": "4.6.1", + "resolved": "https://registry.npmjs.org/npm/-/npm-4.6.1.tgz", + "integrity": "sha1-+Osa0A3FilUUNjtBylNCgX8L1kY=", + "requires": { + "JSONStream": "1.3.1", + "abbrev": "1.1.0", + "ansi-regex": "2.1.1", + "ansicolors": "0.3.2", + "ansistyles": "0.1.3", + "aproba": "1.1.1", + "archy": "1.0.0", + "asap": "2.0.5", + "bluebird": "3.5.0", + "call-limit": "1.1.0", + "chownr": "1.0.1", + "cmd-shim": "2.0.2", + "columnify": "1.5.4", + "config-chain": "1.1.11", + "debuglog": "1.0.1", + "dezalgo": "1.0.3", + "editor": "1.0.0", + "fs-vacuum": "1.2.10", + "fs-write-stream-atomic": "1.0.10", + "fstream": "1.0.11", + "fstream-npm": "1.2.0", + "glob": "7.1.1", + "graceful-fs": "4.1.11", + "has-unicode": "2.0.1", + "hosted-git-info": "2.4.2", + "iferr": "0.1.5", + "imurmurhash": "0.1.4", + "inflight": "1.0.6", + "inherits": "2.0.3", + "ini": "1.3.4", + "init-package-json": "1.10.1", + "lazy-property": "1.0.0", + "lockfile": "1.0.3", + "lodash._baseindexof": "3.1.0", + "lodash._baseuniq": "4.6.0", + "lodash._bindcallback": "3.0.1", + "lodash._cacheindexof": "3.0.2", + "lodash._createcache": "3.1.2", + "lodash._getnative": "3.9.1", + "lodash.clonedeep": "4.5.0", + "lodash.restparam": "3.6.1", + "lodash.union": "4.6.0", + "lodash.uniq": "4.5.0", + "lodash.without": "4.4.0", + "mississippi": "1.3.0", + "mkdirp": "0.5.1", + "move-concurrently": "1.0.1", + "node-gyp": "3.6.0", + "nopt": "4.0.1", + "normalize-git-url": "3.0.2", + "normalize-package-data": "2.3.8", + "npm-cache-filename": "1.0.2", + "npm-install-checks": "3.0.0", + "npm-package-arg": "4.2.1", + "npm-registry-client": "8.1.1", + "npm-user-validate": "0.1.5", + "npmlog": "4.0.2", + "once": "1.4.0", + "opener": "1.4.3", + "osenv": "0.1.4", + "path-is-inside": "1.0.2", + "read": "1.0.7", + "read-cmd-shim": "1.0.1", + "read-installed": "4.0.3", + "read-package-json": "2.0.5", + "read-package-tree": "5.1.5", + "readable-stream": "2.2.9", + "readdir-scoped-modules": "1.0.2", + "realize-package-specifier": "3.0.3", + "request": "2.81.0", + "retry": "0.10.1", + "rimraf": "2.6.1", + "semver": "5.3.0", + "sha": "2.0.1", + "slide": "1.1.6", + "sorted-object": "2.0.1", + "sorted-union-stream": "2.1.3", + "strip-ansi": "3.0.1", + "tar": "2.2.1", + "text-table": "0.2.0", + "uid-number": "0.0.6", + "umask": "1.1.0", + "unique-filename": "1.1.0", + "unpipe": "1.0.0", + "update-notifier": "2.1.0", + "uuid": "3.0.1", + "validate-npm-package-license": "3.0.1", + "validate-npm-package-name": "3.0.0", + "which": "1.2.14", + "wrappy": "1.0.2", + "write-file-atomic": "1.3.3" + }, + "dependencies": { + "JSONStream": { + "version": "1.3.1", + "bundled": true, + "requires": { + "jsonparse": "1.3.0", + "through": "2.3.8" + }, + "dependencies": { + "jsonparse": { + "version": "1.3.0", + "bundled": true + }, + "through": { + "version": "2.3.8", + "bundled": true + } + } + }, + "abbrev": { + "version": "1.1.0", + "bundled": true + }, + "ansi-regex": { + "version": "2.1.1", + "bundled": true + }, + "ansicolors": { + "version": "0.3.2", + "bundled": true + }, + "ansistyles": { + "version": "0.1.3", + "bundled": true + }, + "aproba": { + "version": "1.1.1", + "bundled": true + }, + "archy": { + "version": "1.0.0", + "bundled": true + }, + "asap": { + "version": "2.0.5", + "bundled": true + }, + "bluebird": { + "version": "3.5.0", + "bundled": true + }, + "call-limit": { + "version": "1.1.0", + "bundled": true + }, + "chownr": { + "version": "1.0.1", + "bundled": true + }, + "cmd-shim": { + "version": "2.0.2", + "bundled": true, + "requires": { + "graceful-fs": "4.1.11", + "mkdirp": "0.5.1" + } + }, + "columnify": { + "version": "1.5.4", + "bundled": true, + "requires": { + "strip-ansi": "3.0.1", + "wcwidth": "1.0.0" + }, + "dependencies": { + "wcwidth": { + "version": "1.0.0", + "bundled": true, + "requires": { + "defaults": "1.0.3" + }, + "dependencies": { + "defaults": { + "version": "1.0.3", + "bundled": true, + "requires": { + "clone": "1.0.2" + }, + "dependencies": { + "clone": { + "version": "1.0.2", + "bundled": true + } + } + } + } + } + } + }, + "config-chain": { + "version": "1.1.11", + "bundled": true, + "requires": { + "ini": "1.3.4", + "proto-list": "1.2.4" + }, + "dependencies": { + "proto-list": { + "version": "1.2.4", + "bundled": true + } + } + }, + "debuglog": { + "version": "1.0.1", + "bundled": true + }, + "dezalgo": { + "version": "1.0.3", + "bundled": true, + "requires": { + "asap": "2.0.5", + "wrappy": "1.0.2" + } + }, + "editor": { + "version": "1.0.0", + "bundled": true + }, + "fs-vacuum": { + "version": "1.2.10", + "bundled": true, + "requires": { + "graceful-fs": "4.1.11", + "path-is-inside": "1.0.2", + "rimraf": "2.6.1" + } + }, + "fs-write-stream-atomic": { + "version": "1.0.10", + "bundled": true, + "requires": { + "graceful-fs": "4.1.11", + "iferr": "0.1.5", + "imurmurhash": "0.1.4", + "readable-stream": "2.2.9" + } + }, + "fstream": { + "version": "1.0.11", + "bundled": true, + "requires": { + "graceful-fs": "4.1.11", + "inherits": "2.0.3", + "mkdirp": "0.5.1", + "rimraf": "2.6.1" + } + }, + "fstream-npm": { + "version": "1.2.0", + "bundled": true, + "requires": { + "fstream-ignore": "1.0.5", + "inherits": "2.0.3" + }, + "dependencies": { + "fstream-ignore": { + "version": "1.0.5", + "bundled": true, + "requires": { + "fstream": "1.0.11", + "inherits": "2.0.3", + "minimatch": "3.0.3" + }, + "dependencies": { + "minimatch": { + "version": "3.0.3", + "bundled": true, + "requires": { + "brace-expansion": "1.1.6" + }, + "dependencies": { + "brace-expansion": { + "version": "1.1.6", + "bundled": true, + "requires": { + "balanced-match": "0.4.2", + "concat-map": "0.0.1" + }, + "dependencies": { + "balanced-match": { + "version": "0.4.2", + "bundled": true + }, + "concat-map": { + "version": "0.0.1", + "bundled": true + } + } + } + } + } + } + } + } + }, + "glob": { + "version": "7.1.1", + "bundled": true, + "requires": { + "fs.realpath": "1.0.0", + "inflight": "1.0.6", + "inherits": "2.0.3", + "minimatch": "3.0.3", + "once": "1.4.0", + "path-is-absolute": "1.0.1" + }, + "dependencies": { + "fs.realpath": { + "version": "1.0.0", + "bundled": true + }, + "minimatch": { + "version": "3.0.3", + "bundled": true, + "requires": { + "brace-expansion": "1.1.6" + }, + "dependencies": { + "brace-expansion": { + "version": "1.1.6", + "bundled": true, + "requires": { + "balanced-match": "0.4.2", + "concat-map": "0.0.1" + }, + "dependencies": { + "balanced-match": { + "version": "0.4.2", + "bundled": true + }, + "concat-map": { + "version": "0.0.1", + "bundled": true + } + } + } + } + }, + "path-is-absolute": { + "version": "1.0.1", + "bundled": true + } + } + }, + "graceful-fs": { + "version": "4.1.11", + "bundled": true + }, + "has-unicode": { + "version": "2.0.1", + "bundled": true + }, + "hosted-git-info": { + "version": "2.4.2", + "bundled": true + }, + "iferr": { + "version": "0.1.5", + "bundled": true + }, + "imurmurhash": { + "version": "0.1.4", + "bundled": true + }, + "inflight": { + "version": "1.0.6", + "bundled": true, + "requires": { + "once": "1.4.0", + "wrappy": "1.0.2" + } + }, + "inherits": { + "version": "2.0.3", + "bundled": true + }, + "ini": { + "version": "1.3.4", + "bundled": true + }, + "init-package-json": { + "version": "1.10.1", + "bundled": true, + "requires": { + "glob": "7.1.1", + "npm-package-arg": "4.2.1", + "promzard": "0.3.0", + "read": "1.0.7", + "read-package-json": "2.0.5", + "semver": "5.3.0", + "validate-npm-package-license": "3.0.1", + "validate-npm-package-name": "3.0.0" + }, + "dependencies": { + "promzard": { + "version": "0.3.0", + "bundled": true, + "requires": { + "read": "1.0.7" + } + } + } + }, + "lazy-property": { + "version": "1.0.0", + "bundled": true + }, + "lockfile": { + "version": "1.0.3", + "bundled": true + }, + "lodash._baseindexof": { + "version": "3.1.0", + "bundled": true + }, + "lodash._baseuniq": { + "version": "4.6.0", + "bundled": true, + "requires": { + "lodash._createset": "4.0.3", + "lodash._root": "3.0.1" + }, + "dependencies": { + "lodash._createset": { + "version": "4.0.3", + "bundled": true + }, + "lodash._root": { + "version": "3.0.1", + "bundled": true + } + } + }, + "lodash._bindcallback": { + "version": "3.0.1", + "bundled": true + }, + "lodash._cacheindexof": { + "version": "3.0.2", + "bundled": true + }, + "lodash._createcache": { + "version": "3.1.2", + "bundled": true, + "requires": { + "lodash._getnative": "3.9.1" + } + }, + "lodash._getnative": { + "version": "3.9.1", + "bundled": true + }, + "lodash.clonedeep": { + "version": "4.5.0", + "bundled": true + }, + "lodash.restparam": { + "version": "3.6.1", + "bundled": true + }, + "lodash.union": { + "version": "4.6.0", + "bundled": true + }, + "lodash.uniq": { + "version": "4.5.0", + "bundled": true + }, + "lodash.without": { + "version": "4.4.0", + "bundled": true + }, + "mississippi": { + "version": "1.3.0", + "bundled": true, + "requires": { + "concat-stream": "1.6.0", + "duplexify": "3.5.0", + "end-of-stream": "1.1.0", + "flush-write-stream": "1.0.2", + "from2": "2.3.0", + "parallel-transform": "1.1.0", + "pump": "1.0.2", + "pumpify": "1.3.5", + "stream-each": "1.2.0", + "through2": "2.0.3" + }, + "dependencies": { + "concat-stream": { + "version": "1.6.0", + "bundled": true, + "requires": { + "inherits": "2.0.3", + "readable-stream": "2.2.9", + "typedarray": "0.0.6" + }, + "dependencies": { + "typedarray": { + "version": "0.0.6", + "bundled": true + } + } + }, + "duplexify": { + "version": "3.5.0", + "bundled": true, + "requires": { + "end-of-stream": "1.0.0", + "inherits": "2.0.3", + "readable-stream": "2.2.9", + "stream-shift": "1.0.0" + }, + "dependencies": { + "end-of-stream": { + "version": "1.0.0", + "bundled": true, + "requires": { + "once": "1.3.3" + }, + "dependencies": { + "once": { + "version": "1.3.3", + "bundled": true, + "requires": { + "wrappy": "1.0.2" + } + } + } + }, + "stream-shift": { + "version": "1.0.0", + "bundled": true + } + } + }, + "end-of-stream": { + "version": "1.1.0", + "bundled": true, + "requires": { + "once": "1.3.3" + }, + "dependencies": { + "once": { + "version": "1.3.3", + "bundled": true, + "requires": { + "wrappy": "1.0.2" + } + } + } + }, + "flush-write-stream": { + "version": "1.0.2", + "bundled": true, + "requires": { + "inherits": "2.0.3", + "readable-stream": "2.2.9" + } + }, + "from2": { + "version": "2.3.0", + "bundled": true, + "requires": { + "inherits": "2.0.3", + "readable-stream": "2.2.9" + } + }, + "parallel-transform": { + "version": "1.1.0", + "bundled": true, + "requires": { + "cyclist": "0.2.2", + "inherits": "2.0.3", + "readable-stream": "2.2.9" + }, + "dependencies": { + "cyclist": { + "version": "0.2.2", + "bundled": true + } + } + }, + "pump": { + "version": "1.0.2", + "bundled": true, + "requires": { + "end-of-stream": "1.1.0", + "once": "1.4.0" + } + }, + "pumpify": { + "version": "1.3.5", + "bundled": true, + "requires": { + "duplexify": "3.5.0", + "inherits": "2.0.3", + "pump": "1.0.2" + } + }, + "stream-each": { + "version": "1.2.0", + "bundled": true, + "requires": { + "end-of-stream": "1.1.0", + "stream-shift": "1.0.0" + }, + "dependencies": { + "stream-shift": { + "version": "1.0.0", + "bundled": true + } + } + }, + "through2": { + "version": "2.0.3", + "bundled": true, + "requires": { + "readable-stream": "2.2.9", + "xtend": "4.0.1" + }, + "dependencies": { + "xtend": { + "version": "4.0.1", + "bundled": true + } + } + } + } + }, + "mkdirp": { + "version": "0.5.1", + "bundled": true, + "requires": { + "minimist": "0.0.8" + }, + "dependencies": { + "minimist": { + "version": "0.0.8", + "bundled": true + } + } + }, + "move-concurrently": { + "version": "1.0.1", + "bundled": true, + "requires": { + "aproba": "1.1.1", + "copy-concurrently": "1.0.3", + "fs-write-stream-atomic": "1.0.10", + "mkdirp": "0.5.1", + "rimraf": "2.6.1", + "run-queue": "1.0.3" + }, + "dependencies": { + "copy-concurrently": { + "version": "1.0.3", + "bundled": true, + "requires": { + "aproba": "1.1.1", + "fs-write-stream-atomic": "1.0.10", + "iferr": "0.1.5", + "mkdirp": "0.5.1", + "rimraf": "2.6.1", + "run-queue": "1.0.3" + } + }, + "run-queue": { + "version": "1.0.3", + "bundled": true, + "requires": { + "aproba": "1.1.1" + } + } + } + }, + "node-gyp": { + "version": "3.6.0", + "bundled": true, + "requires": { + "fstream": "1.0.11", + "glob": "7.1.1", + "graceful-fs": "4.1.11", + "minimatch": "3.0.3", + "mkdirp": "0.5.1", + "nopt": "3.0.6", + "npmlog": "4.0.2", + "osenv": "0.1.4", + "request": "2.81.0", + "rimraf": "2.6.1", + "semver": "5.3.0", + "tar": "2.2.1", + "which": "1.2.14" + }, + "dependencies": { + "minimatch": { + "version": "3.0.3", + "bundled": true, + "requires": { + "brace-expansion": "1.1.6" + }, + "dependencies": { + "brace-expansion": { + "version": "1.1.6", + "bundled": true, + "requires": { + "balanced-match": "0.4.2", + "concat-map": "0.0.1" + }, + "dependencies": { + "balanced-match": { + "version": "0.4.2", + "bundled": true + }, + "concat-map": { + "version": "0.0.1", + "bundled": true + } + } + } + } + }, + "nopt": { + "version": "3.0.6", + "bundled": true, + "requires": { + "abbrev": "1.1.0" + } + } + } + }, + "nopt": { + "version": "4.0.1", + "bundled": true, + "requires": { + "abbrev": "1.1.0", + "osenv": "0.1.4" + }, + "dependencies": { + "osenv": { + "version": "0.1.4", + "bundled": true, + "requires": { + "os-homedir": "1.0.2", + "os-tmpdir": "1.0.2" + }, + "dependencies": { + "os-homedir": { + "version": "1.0.2", + "bundled": true + }, + "os-tmpdir": { + "version": "1.0.2", + "bundled": true + } + } + } + } + }, + "normalize-git-url": { + "version": "3.0.2", + "bundled": true + }, + "normalize-package-data": { + "version": "2.3.8", + "bundled": true, + "requires": { + "hosted-git-info": "2.4.2", + "is-builtin-module": "1.0.0", + "semver": "5.3.0", + "validate-npm-package-license": "3.0.1" + }, + "dependencies": { + "is-builtin-module": { + "version": "1.0.0", + "bundled": true, + "requires": { + "builtin-modules": "1.1.1" + }, + "dependencies": { + "builtin-modules": { + "version": "1.1.1", + "bundled": true + } + } + } + } + }, + "npm-cache-filename": { + "version": "1.0.2", + "bundled": true + }, + "npm-install-checks": { + "version": "3.0.0", + "bundled": true, + "requires": { + "semver": "5.3.0" + } + }, + "npm-package-arg": { + "version": "4.2.1", + "bundled": true, + "requires": { + "hosted-git-info": "2.4.2", + "semver": "5.3.0" + } + }, + "npm-registry-client": { + "version": "8.1.1", + "bundled": true, + "requires": { + "concat-stream": "1.6.0", + "graceful-fs": "4.1.11", + "normalize-package-data": "2.3.8", + "npm-package-arg": "4.2.1", + "npmlog": "4.0.2", + "once": "1.4.0", + "request": "2.81.0", + "retry": "0.10.1", + "semver": "5.3.0", + "slide": "1.1.6" + }, + "dependencies": { + "concat-stream": { + "version": "1.6.0", + "bundled": true, + "requires": { + "inherits": "2.0.3", + "readable-stream": "2.2.9", + "typedarray": "0.0.6" + }, + "dependencies": { + "typedarray": { + "version": "0.0.6", + "bundled": true + } + } + } + } + }, + "npm-user-validate": { + "version": "0.1.5", + "bundled": true + }, + "npmlog": { + "version": "4.0.2", + "bundled": true, + "requires": { + "are-we-there-yet": "1.1.4", + "console-control-strings": "1.1.0", + "gauge": "2.7.4", + "set-blocking": "2.0.0" + }, + "dependencies": { + "are-we-there-yet": { + "version": "1.1.4", + "bundled": true, + "requires": { + "delegates": "1.0.0", + "readable-stream": "2.2.9" + }, + "dependencies": { + "delegates": { + "version": "1.0.0", + "bundled": true + } + } + }, + "console-control-strings": { + "version": "1.1.0", + "bundled": true + }, + "gauge": { + "version": "2.7.4", + "bundled": true, + "requires": { + "aproba": "1.1.1", + "console-control-strings": "1.1.0", + "has-unicode": "2.0.1", + "object-assign": "4.1.1", + "signal-exit": "3.0.2", + "string-width": "1.0.2", + "strip-ansi": "3.0.1", + "wide-align": "1.1.0" + }, + "dependencies": { + "object-assign": { + "version": "4.1.1", + "bundled": true + }, + "signal-exit": { + "version": "3.0.2", + "bundled": true + }, + "string-width": { + "version": "1.0.2", + "bundled": true, + "requires": { + "code-point-at": "1.1.0", + "is-fullwidth-code-point": "1.0.0", + "strip-ansi": "3.0.1" + }, + "dependencies": { + "code-point-at": { + "version": "1.1.0", + "bundled": true + }, + "is-fullwidth-code-point": { + "version": "1.0.0", + "bundled": true, + "requires": { + "number-is-nan": "1.0.1" + }, + "dependencies": { + "number-is-nan": { + "version": "1.0.1", + "bundled": true + } + } + } + } + }, + "wide-align": { + "version": "1.1.0", + "bundled": true, + "requires": { + "string-width": "1.0.2" + } + } + } + }, + "set-blocking": { + "version": "2.0.0", + "bundled": true + } + } + }, + "once": { + "version": "1.4.0", + "bundled": true, + "requires": { + "wrappy": "1.0.2" + } + }, + "opener": { + "version": "1.4.3", + "bundled": true + }, + "osenv": { + "version": "0.1.4", + "bundled": true, + "requires": { + "os-homedir": "1.0.2", + "os-tmpdir": "1.0.2" + }, + "dependencies": { + "os-homedir": { + "version": "1.0.2", + "bundled": true + }, + "os-tmpdir": { + "version": "1.0.2", + "bundled": true + } + } + }, + "path-is-inside": { + "version": "1.0.2", + "bundled": true + }, + "read": { + "version": "1.0.7", + "bundled": true, + "requires": { + "mute-stream": "0.0.5" + }, + "dependencies": { + "mute-stream": { + "version": "0.0.5", + "bundled": true + } + } + }, + "read-cmd-shim": { + "version": "1.0.1", + "bundled": true, + "requires": { + "graceful-fs": "4.1.11" + } + }, + "read-installed": { + "version": "4.0.3", + "bundled": true, + "requires": { + "debuglog": "1.0.1", + "graceful-fs": "4.1.11", + "read-package-json": "2.0.5", + "readdir-scoped-modules": "1.0.2", + "semver": "5.3.0", + "slide": "1.1.6", + "util-extend": "1.0.3" + }, + "dependencies": { + "util-extend": { + "version": "1.0.3", + "bundled": true + } + } + }, + "read-package-json": { + "version": "2.0.5", + "bundled": true, + "requires": { + "glob": "7.1.1", + "graceful-fs": "4.1.11", + "json-parse-helpfulerror": "1.0.3", + "normalize-package-data": "2.3.8" + }, + "dependencies": { + "json-parse-helpfulerror": { + "version": "1.0.3", + "bundled": true, + "requires": { + "jju": "1.3.0" + }, + "dependencies": { + "jju": { + "version": "1.3.0", + "bundled": true + } + } + } + } + }, + "read-package-tree": { + "version": "5.1.5", + "bundled": true, + "requires": { + "debuglog": "1.0.1", + "dezalgo": "1.0.3", + "once": "1.4.0", + "read-package-json": "2.0.5", + "readdir-scoped-modules": "1.0.2" + } + }, + "readable-stream": { + "version": "2.2.9", + "bundled": true, + "requires": { + "buffer-shims": "1.0.0", + "core-util-is": "1.0.2", + "inherits": "2.0.3", + "isarray": "1.0.0", + "process-nextick-args": "1.0.7", + "string_decoder": "1.0.0", + "util-deprecate": "1.0.2" + }, + "dependencies": { + "buffer-shims": { + "version": "1.0.0", + "bundled": true + }, + "core-util-is": { + "version": "1.0.2", + "bundled": true + }, + "isarray": { + "version": "1.0.0", + "bundled": true + }, + "process-nextick-args": { + "version": "1.0.7", + "bundled": true + }, + "string_decoder": { + "version": "1.0.0", + "bundled": true, + "requires": { + "buffer-shims": "1.0.0" + } + }, + "util-deprecate": { + "version": "1.0.2", + "bundled": true + } + } + }, + "readdir-scoped-modules": { + "version": "1.0.2", + "bundled": true, + "requires": { + "debuglog": "1.0.1", + "dezalgo": "1.0.3", + "graceful-fs": "4.1.11", + "once": "1.4.0" + } + }, + "realize-package-specifier": { + "version": "3.0.3", + "bundled": true, + "requires": { + "dezalgo": "1.0.3", + "npm-package-arg": "4.2.1" + } + }, + "request": { + "version": "2.81.0", + "bundled": true, + "requires": { + "aws-sign2": "0.6.0", + "aws4": "1.6.0", + "caseless": "0.12.0", + "combined-stream": "1.0.5", + "extend": "3.0.0", + "forever-agent": "0.6.1", + "form-data": "2.1.2", + "har-validator": "4.2.1", + "hawk": "3.1.3", + "http-signature": "1.1.1", + "is-typedarray": "1.0.0", + "isstream": "0.1.2", + "json-stringify-safe": "5.0.1", + "mime-types": "2.1.14", + "oauth-sign": "0.8.2", + "performance-now": "0.2.0", + "qs": "6.4.0", + "safe-buffer": "5.0.1", + "stringstream": "0.0.5", + "tough-cookie": "2.3.2", + "tunnel-agent": "0.6.0", + "uuid": "3.0.1" + }, + "dependencies": { + "aws-sign2": { + "version": "0.6.0", + "bundled": true + }, + "aws4": { + "version": "1.6.0", + "bundled": true + }, + "caseless": { + "version": "0.12.0", + "bundled": true + }, + "combined-stream": { + "version": "1.0.5", + "bundled": true, + "requires": { + "delayed-stream": "1.0.0" + }, + "dependencies": { + "delayed-stream": { + "version": "1.0.0", + "bundled": true + } + } + }, + "extend": { + "version": "3.0.0", + "bundled": true + }, + "forever-agent": { + "version": "0.6.1", + "bundled": true + }, + "form-data": { + "version": "2.1.2", + "bundled": true, + "requires": { + "asynckit": "0.4.0", + "combined-stream": "1.0.5", + "mime-types": "2.1.14" + }, + "dependencies": { + "asynckit": { + "version": "0.4.0", + "bundled": true + } + } + }, + "har-validator": { + "version": "4.2.1", + "bundled": true, + "requires": { + "ajv": "4.11.4", + "har-schema": "1.0.5" + }, + "dependencies": { + "ajv": { + "version": "4.11.4", + "bundled": true, + "requires": { + "co": "4.6.0", + "json-stable-stringify": "1.0.1" + }, + "dependencies": { + "co": { + "version": "4.6.0", + "bundled": true + }, + "json-stable-stringify": { + "version": "1.0.1", + "bundled": true, + "requires": { + "jsonify": "0.0.0" + }, + "dependencies": { + "jsonify": { + "version": "0.0.0", + "bundled": true + } + } + } + } + }, + "har-schema": { + "version": "1.0.5", + "bundled": true + } + } + }, + "hawk": { + "version": "3.1.3", + "bundled": true, + "requires": { + "boom": "2.10.1", + "cryptiles": "2.0.5", + "hoek": "2.16.3", + "sntp": "1.0.9" + }, + "dependencies": { + "boom": { + "version": "2.10.1", + "bundled": true, + "requires": { + "hoek": "2.16.3" + } + }, + "cryptiles": { + "version": "2.0.5", + "bundled": true, + "requires": { + "boom": "2.10.1" + } + }, + "hoek": { + "version": "2.16.3", + "bundled": true + }, + "sntp": { + "version": "1.0.9", + "bundled": true, + "requires": { + "hoek": "2.16.3" + } + } + } + }, + "http-signature": { + "version": "1.1.1", + "bundled": true, + "requires": { + "assert-plus": "0.2.0", + "jsprim": "1.3.1", + "sshpk": "1.11.0" + }, + "dependencies": { + "assert-plus": { + "version": "0.2.0", + "bundled": true + }, + "jsprim": { + "version": "1.3.1", + "bundled": true, + "requires": { + "extsprintf": "1.0.2", + "json-schema": "0.2.3", + "verror": "1.3.6" + }, + "dependencies": { + "extsprintf": { + "version": "1.0.2", + "bundled": true + }, + "json-schema": { + "version": "0.2.3", + "bundled": true + }, + "verror": { + "version": "1.3.6", + "bundled": true, + "requires": { + "extsprintf": "1.0.2" + } + } + } + }, + "sshpk": { + "version": "1.11.0", + "bundled": true, + "requires": { + "asn1": "0.2.3", + "assert-plus": "1.0.0", + "bcrypt-pbkdf": "1.0.1", + "dashdash": "1.14.1", + "ecc-jsbn": "0.1.1", + "getpass": "0.1.6", + "jodid25519": "1.0.2", + "jsbn": "0.1.1", + "tweetnacl": "0.14.5" + }, + "dependencies": { + "asn1": { + "version": "0.2.3", + "bundled": true + }, + "assert-plus": { + "version": "1.0.0", + "bundled": true + }, + "bcrypt-pbkdf": { + "version": "1.0.1", + "bundled": true, + "optional": true, + "requires": { + "tweetnacl": "0.14.5" + } + }, + "dashdash": { + "version": "1.14.1", + "bundled": true, + "requires": { + "assert-plus": "1.0.0" + } + }, + "ecc-jsbn": { + "version": "0.1.1", + "bundled": true, + "optional": true, + "requires": { + "jsbn": "0.1.1" + } + }, + "getpass": { + "version": "0.1.6", + "bundled": true, + "requires": { + "assert-plus": "1.0.0" + } + }, + "jodid25519": { + "version": "1.0.2", + "bundled": true, + "optional": true, + "requires": { + "jsbn": "0.1.1" + } + }, + "jsbn": { + "version": "0.1.1", + "bundled": true, + "optional": true + }, + "tweetnacl": { + "version": "0.14.5", + "bundled": true, + "optional": true + } + } + } + } + }, + "is-typedarray": { + "version": "1.0.0", + "bundled": true + }, + "isstream": { + "version": "0.1.2", + "bundled": true + }, + "json-stringify-safe": { + "version": "5.0.1", + "bundled": true + }, + "mime-types": { + "version": "2.1.14", + "bundled": true, + "requires": { + "mime-db": "1.26.0" + }, + "dependencies": { + "mime-db": { + "version": "1.26.0", + "bundled": true + } + } + }, + "oauth-sign": { + "version": "0.8.2", + "bundled": true + }, + "performance-now": { + "version": "0.2.0", + "bundled": true + }, + "qs": { + "version": "6.4.0", + "bundled": true + }, + "safe-buffer": { + "version": "5.0.1", + "bundled": true + }, + "stringstream": { + "version": "0.0.5", + "bundled": true + }, + "tough-cookie": { + "version": "2.3.2", + "bundled": true, + "requires": { + "punycode": "1.4.1" + }, + "dependencies": { + "punycode": { + "version": "1.4.1", + "bundled": true + } + } + }, + "tunnel-agent": { + "version": "0.6.0", + "bundled": true, + "requires": { + "safe-buffer": "5.0.1" + } + } + } + }, + "retry": { + "version": "0.10.1", + "bundled": true + }, + "rimraf": { + "version": "2.6.1", + "bundled": true, + "requires": { + "glob": "7.1.1" + } + }, + "semver": { + "version": "5.3.0", + "bundled": true + }, + "sha": { + "version": "2.0.1", + "bundled": true, + "requires": { + "graceful-fs": "4.1.11", + "readable-stream": "2.2.9" + } + }, + "slide": { + "version": "1.1.6", + "bundled": true + }, + "sorted-object": { + "version": "2.0.1", + "bundled": true + }, + "sorted-union-stream": { + "version": "2.1.3", + "bundled": true, + "requires": { + "from2": "1.3.0", + "stream-iterate": "1.1.1" + }, + "dependencies": { + "from2": { + "version": "1.3.0", + "bundled": true, + "requires": { + "inherits": "2.0.3", + "readable-stream": "1.1.14" + }, + "dependencies": { + "readable-stream": { + "version": "1.1.14", + "bundled": true, + "requires": { + "core-util-is": "1.0.2", + "inherits": "2.0.3", + "isarray": "0.0.1", + "string_decoder": "0.10.31" + }, + "dependencies": { + "core-util-is": { + "version": "1.0.2", + "bundled": true + }, + "isarray": { + "version": "0.0.1", + "bundled": true + }, + "string_decoder": { + "version": "0.10.31", + "bundled": true + } + } + } + } + }, + "stream-iterate": { + "version": "1.1.1", + "bundled": true + } + } + }, + "strip-ansi": { + "version": "3.0.1", + "bundled": true, + "requires": { + "ansi-regex": "2.1.1" + } + }, + "tar": { + "version": "2.2.1", + "bundled": true, + "requires": { + "block-stream": "0.0.8", + "fstream": "1.0.11", + "inherits": "2.0.3" + }, + "dependencies": { + "block-stream": { + "version": "0.0.8", + "bundled": true, + "requires": { + "inherits": "2.0.3" + } + } + } + }, + "text-table": { + "version": "0.2.0", + "bundled": true + }, + "uid-number": { + "version": "0.0.6", + "bundled": true + }, + "umask": { + "version": "1.1.0", + "bundled": true + }, + "unique-filename": { + "version": "1.1.0", + "bundled": true, + "requires": { + "unique-slug": "2.0.0" + }, + "dependencies": { + "unique-slug": { + "version": "2.0.0", + "bundled": true, + "requires": { + "imurmurhash": "0.1.4" + } + } + } + }, + "unpipe": { + "version": "1.0.0", + "bundled": true + }, + "update-notifier": { + "version": "2.1.0", + "bundled": true, + "requires": { + "boxen": "1.0.0", + "chalk": "1.1.3", + "configstore": "3.0.0", + "is-npm": "1.0.0", + "latest-version": "3.0.0", + "lazy-req": "2.0.0", + "semver-diff": "2.1.0", + "xdg-basedir": "3.0.0" + }, + "dependencies": { + "boxen": { + "version": "1.0.0", + "bundled": true, + "requires": { + "ansi-align": "1.1.0", + "camelcase": "4.0.0", + "chalk": "1.1.3", + "cli-boxes": "1.0.0", + "string-width": "2.0.0", + "term-size": "0.1.1", + "widest-line": "1.0.0" + }, + "dependencies": { + "ansi-align": { + "version": "1.1.0", + "bundled": true, + "requires": { + "string-width": "1.0.2" + }, + "dependencies": { + "string-width": { + "version": "1.0.2", + "bundled": true, + "requires": { + "code-point-at": "1.1.0", + "is-fullwidth-code-point": "1.0.0", + "strip-ansi": "3.0.1" + }, + "dependencies": { + "code-point-at": { + "version": "1.1.0", + "bundled": true + }, + "is-fullwidth-code-point": { + "version": "1.0.0", + "bundled": true, + "requires": { + "number-is-nan": "1.0.1" + }, + "dependencies": { + "number-is-nan": { + "version": "1.0.1", + "bundled": true + } + } + } + } + } + } + }, + "camelcase": { + "version": "4.0.0", + "bundled": true + }, + "cli-boxes": { + "version": "1.0.0", + "bundled": true + }, + "string-width": { + "version": "2.0.0", + "bundled": true, + "requires": { + "is-fullwidth-code-point": "2.0.0", + "strip-ansi": "3.0.1" + }, + "dependencies": { + "is-fullwidth-code-point": { + "version": "2.0.0", + "bundled": true + } + } + }, + "term-size": { + "version": "0.1.1", + "bundled": true, + "requires": { + "execa": "0.4.0" + }, + "dependencies": { + "execa": { + "version": "0.4.0", + "bundled": true, + "requires": { + "cross-spawn-async": "2.2.5", + "is-stream": "1.1.0", + "npm-run-path": "1.0.0", + "object-assign": "4.1.1", + "path-key": "1.0.0", + "strip-eof": "1.0.0" + }, + "dependencies": { + "cross-spawn-async": { + "version": "2.2.5", + "bundled": true, + "requires": { + "lru-cache": "4.0.2", + "which": "1.2.14" + }, + "dependencies": { + "lru-cache": { + "version": "4.0.2", + "bundled": true, + "requires": { + "pseudomap": "1.0.2", + "yallist": "2.0.0" + }, + "dependencies": { + "pseudomap": { + "version": "1.0.2", + "bundled": true + }, + "yallist": { + "version": "2.0.0", + "bundled": true + } + } + } + } + }, + "is-stream": { + "version": "1.1.0", + "bundled": true + }, + "npm-run-path": { + "version": "1.0.0", + "bundled": true, + "requires": { + "path-key": "1.0.0" + } + }, + "object-assign": { + "version": "4.1.1", + "bundled": true + }, + "path-key": { + "version": "1.0.0", + "bundled": true + }, + "strip-eof": { + "version": "1.0.0", + "bundled": true + } + } + } + } + }, + "widest-line": { + "version": "1.0.0", + "bundled": true, + "requires": { + "string-width": "1.0.2" + }, + "dependencies": { + "string-width": { + "version": "1.0.2", + "bundled": true, + "requires": { + "code-point-at": "1.1.0", + "is-fullwidth-code-point": "1.0.0", + "strip-ansi": "3.0.1" + }, + "dependencies": { + "code-point-at": { + "version": "1.1.0", + "bundled": true + }, + "is-fullwidth-code-point": { + "version": "1.0.0", + "bundled": true, + "requires": { + "number-is-nan": "1.0.1" + }, + "dependencies": { + "number-is-nan": { + "version": "1.0.1", + "bundled": true + } + } + } + } + } + } + } + } + }, + "chalk": { + "version": "1.1.3", + "bundled": true, + "requires": { + "ansi-styles": "2.2.1", + "escape-string-regexp": "1.0.5", + "has-ansi": "2.0.0", + "strip-ansi": "3.0.1", + "supports-color": "2.0.0" + }, + "dependencies": { + "ansi-styles": { + "version": "2.2.1", + "bundled": true + }, + "escape-string-regexp": { + "version": "1.0.5", + "bundled": true + }, + "has-ansi": { + "version": "2.0.0", + "bundled": true, + "requires": { + "ansi-regex": "2.1.1" + } + }, + "supports-color": { + "version": "2.0.0", + "bundled": true + } + } + }, + "configstore": { + "version": "3.0.0", + "bundled": true, + "requires": { + "dot-prop": "4.1.1", + "graceful-fs": "4.1.11", + "mkdirp": "0.5.1", + "unique-string": "1.0.0", + "write-file-atomic": "1.3.3", + "xdg-basedir": "3.0.0" + }, + "dependencies": { + "dot-prop": { + "version": "4.1.1", + "bundled": true, + "requires": { + "is-obj": "1.0.1" + }, + "dependencies": { + "is-obj": { + "version": "1.0.1", + "bundled": true + } + } + }, + "unique-string": { + "version": "1.0.0", + "bundled": true, + "requires": { + "crypto-random-string": "1.0.0" + }, + "dependencies": { + "crypto-random-string": { + "version": "1.0.0", + "bundled": true + } + } + } + } + }, + "is-npm": { + "version": "1.0.0", + "bundled": true + }, + "latest-version": { + "version": "3.0.0", + "bundled": true, + "requires": { + "package-json": "3.1.0" + }, + "dependencies": { + "package-json": { + "version": "3.1.0", + "bundled": true, + "requires": { + "got": "6.7.1", + "registry-auth-token": "3.1.0", + "registry-url": "3.1.0", + "semver": "5.3.0" + }, + "dependencies": { + "got": { + "version": "6.7.1", + "bundled": true, + "requires": { + "create-error-class": "3.0.2", + "duplexer3": "0.1.4", + "get-stream": "3.0.0", + "is-redirect": "1.0.0", + "is-retry-allowed": "1.1.0", + "is-stream": "1.1.0", + "lowercase-keys": "1.0.0", + "safe-buffer": "5.0.1", + "timed-out": "4.0.1", + "unzip-response": "2.0.1", + "url-parse-lax": "1.0.0" + }, + "dependencies": { + "create-error-class": { + "version": "3.0.2", + "bundled": true, + "requires": { + "capture-stack-trace": "1.0.0" + }, + "dependencies": { + "capture-stack-trace": { + "version": "1.0.0", + "bundled": true + } + } + }, + "duplexer3": { + "version": "0.1.4", + "bundled": true + }, + "get-stream": { + "version": "3.0.0", + "bundled": true + }, + "is-redirect": { + "version": "1.0.0", + "bundled": true + }, + "is-retry-allowed": { + "version": "1.1.0", + "bundled": true + }, + "is-stream": { + "version": "1.1.0", + "bundled": true + }, + "lowercase-keys": { + "version": "1.0.0", + "bundled": true + }, + "safe-buffer": { + "version": "5.0.1", + "bundled": true + }, + "timed-out": { + "version": "4.0.1", + "bundled": true + }, + "unzip-response": { + "version": "2.0.1", + "bundled": true + }, + "url-parse-lax": { + "version": "1.0.0", + "bundled": true, + "requires": { + "prepend-http": "1.0.4" + }, + "dependencies": { + "prepend-http": { + "version": "1.0.4", + "bundled": true + } + } + } + } + }, + "registry-auth-token": { + "version": "3.1.0", + "bundled": true, + "requires": { + "rc": "1.1.7" + }, + "dependencies": { + "rc": { + "version": "1.1.7", + "bundled": true, + "requires": { + "deep-extend": "0.4.1", + "ini": "1.3.4", + "minimist": "1.2.0", + "strip-json-comments": "2.0.1" + }, + "dependencies": { + "deep-extend": { + "version": "0.4.1", + "bundled": true + }, + "minimist": { + "version": "1.2.0", + "bundled": true + }, + "strip-json-comments": { + "version": "2.0.1", + "bundled": true + } + } + } + } + }, + "registry-url": { + "version": "3.1.0", + "bundled": true, + "requires": { + "rc": "1.1.7" + }, + "dependencies": { + "rc": { + "version": "1.1.7", + "bundled": true, + "requires": { + "deep-extend": "0.4.1", + "ini": "1.3.4", + "minimist": "1.2.0", + "strip-json-comments": "2.0.1" + }, + "dependencies": { + "deep-extend": { + "version": "0.4.1", + "bundled": true + }, + "minimist": { + "version": "1.2.0", + "bundled": true + }, + "strip-json-comments": { + "version": "2.0.1", + "bundled": true + } + } + } + } + } + } + } + } + }, + "lazy-req": { + "version": "2.0.0", + "bundled": true + }, + "semver-diff": { + "version": "2.1.0", + "bundled": true, + "requires": { + "semver": "5.3.0" + } + }, + "xdg-basedir": { + "version": "3.0.0", + "bundled": true + } + } + }, + "uuid": { + "version": "3.0.1", + "bundled": true + }, + "validate-npm-package-license": { + "version": "3.0.1", + "bundled": true, + "requires": { + "spdx-correct": "1.0.2", + "spdx-expression-parse": "1.0.2" + }, + "dependencies": { + "spdx-correct": { + "version": "1.0.2", + "bundled": true, + "requires": { + "spdx-license-ids": "1.2.0" + }, + "dependencies": { + "spdx-license-ids": { + "version": "1.2.0", + "bundled": true + } + } + }, + "spdx-expression-parse": { + "version": "1.0.2", + "bundled": true, + "requires": { + "spdx-exceptions": "1.0.4", + "spdx-license-ids": "1.2.0" + }, + "dependencies": { + "spdx-exceptions": { + "version": "1.0.4", + "bundled": true + }, + "spdx-license-ids": { + "version": "1.2.0", + "bundled": true + } + } + } + } + }, + "validate-npm-package-name": { + "version": "3.0.0", + "bundled": true, + "requires": { + "builtins": "1.0.3" + }, + "dependencies": { + "builtins": { + "version": "1.0.3", + "bundled": true + } + } + }, + "which": { + "version": "1.2.14", + "bundled": true, + "requires": { + "isexe": "2.0.0" + }, + "dependencies": { + "isexe": { + "version": "2.0.0", + "bundled": true + } + } + }, + "wrappy": { + "version": "1.0.2", + "bundled": true + }, + "write-file-atomic": { + "version": "1.3.3", + "bundled": true, + "requires": { + "graceful-fs": "4.1.11", + "imurmurhash": "0.1.4", + "slide": "1.1.6" + } + } + } + }, + "npmlog": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/npmlog/-/npmlog-4.1.2.tgz", + "integrity": "sha512-2uUqazuKlTaSI/dC8AzicUck7+IrEaOnN/e0jd3Xtt1KcGpwx30v50mL7oPyr/h9bL3E4aZccVwpwP+5W9Vjkg==", + "requires": { + "are-we-there-yet": "1.1.4", + "console-control-strings": "1.1.0", + "gauge": "2.7.4", + "set-blocking": "2.0.0" + } + }, + "number-is-nan": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/number-is-nan/-/number-is-nan-1.0.1.tgz", + "integrity": "sha1-CXtgK1NCKlIsGvuHkDGDNpQaAR0=" + }, + "object-assign": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", + "integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=" + }, + "object-inspect": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-0.4.0.tgz", + "integrity": "sha1-9RV8EWwUVbJDsG7pdwM5LFrYn+w=" + }, + "object-keys": { + "version": "1.0.11", + "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.0.11.tgz", + "integrity": "sha1-xUYBd4rVYPEULODgG8yotW0TQm0=" + }, + "object.entries": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/object.entries/-/object.entries-1.0.4.tgz", + "integrity": "sha1-G/mk3SKI9bM/Opk9JXZh8F0WGl8=", + "requires": { + "define-properties": "1.1.2", + "es-abstract": "1.9.0", + "function-bind": "1.1.1", + "has": "1.0.1" + } + }, + "once": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", + "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", + "requires": { + "wrappy": "1.0.2" + } + }, + "optimist": { + "version": "0.3.7", + "resolved": "https://registry.npmjs.org/optimist/-/optimist-0.3.7.tgz", + "integrity": "sha1-yQlBrVnkJzMokjB00s8ufLxuwNk=", + "requires": { + "wordwrap": "0.0.3" + } + }, + "os-browserify": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/os-browserify/-/os-browserify-0.3.0.tgz", + "integrity": "sha1-hUNzx/XCMVkU/Jv8a9gjj92h7Cc=" + }, + "os-homedir": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/os-homedir/-/os-homedir-1.0.2.tgz", + "integrity": "sha1-/7xJiDNuDoM94MFox+8VISGqf7M=" + }, + "os-locale": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/os-locale/-/os-locale-1.4.0.tgz", + "integrity": "sha1-IPnxeuKe00XoveWDsT0gCYA8FNk=", + "requires": { + "lcid": "1.0.0" + } + }, + "os-tmpdir": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/os-tmpdir/-/os-tmpdir-1.0.2.tgz", + "integrity": "sha1-u+Z0BseaqFxc/sdm/lc0VV36EnQ=" + }, + "p-any": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/p-any/-/p-any-1.1.0.tgz", + "integrity": "sha512-Ef0tVa4CZ5pTAmKn+Cg3w8ABBXh+hHO1aV8281dKOoUHfX+3tjG2EaFcC+aZyagg9b4EYGsHEjz21DnEE8Og2g==", + "requires": { + "p-some": "2.0.0" + } + }, + "p-finally": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/p-finally/-/p-finally-1.0.0.tgz", + "integrity": "sha1-P7z7FbiZpEEjs0ttzBi3JDNqLK4=" + }, + "p-some": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/p-some/-/p-some-2.0.0.tgz", + "integrity": "sha512-CsRc5gwQNJgSh+pNaGUtgBWBSh9btl8jYLbIdeqLgOLAATZmDDX7xTS5V0mqJk5Dw0gz8FF6s8sAF4D0MvxLhw==", + "requires": { + "aggregate-error": "1.0.0" + } + }, + "p-timeout": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/p-timeout/-/p-timeout-1.2.0.tgz", + "integrity": "sha1-mCD5lDTFgXhotPNICe5SkWYNW2w=", + "requires": { + "p-finally": "1.0.0" + } + }, + "pako": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/pako/-/pako-1.0.6.tgz", + "integrity": "sha512-lQe48YPsMJAig+yngZ87Lus+NF+3mtu7DVOBu6b/gHO1YpKwIj5AWjZ/TOS7i46HD/UixzWb1zeWDZfGZ3iYcg==" + }, + "parents": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/parents/-/parents-1.0.1.tgz", + "integrity": "sha1-/t1NK/GTp3dF/nHjcdc8MwfZx1E=", + "requires": { + "path-platform": "0.11.15" + } + }, + "parse-asn1": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/parse-asn1/-/parse-asn1-5.1.0.tgz", + "integrity": "sha1-N8T5t+06tlx0gXtfJICTf7+XxxI=", + "requires": { + "asn1.js": "4.9.2", + "browserify-aes": "1.1.1", + "create-hash": "1.1.3", + "evp_bytestokey": "1.0.3", + "pbkdf2": "3.0.14" + } + }, + "parse-json": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-2.2.0.tgz", + "integrity": "sha1-9ID0BDTvgHQfhGkJn43qGPVaTck=", + "requires": { + "error-ex": "1.3.1" + } + }, + "path-browserify": { + "version": "0.0.0", + "resolved": "https://registry.npmjs.org/path-browserify/-/path-browserify-0.0.0.tgz", + "integrity": "sha1-oLhwcpquIUAFt9UDLsLLuw+0RRo=" + }, + "path-exists": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-2.1.0.tgz", + "integrity": "sha1-D+tsZPD8UY2adU3V77YscCJ2H0s=", + "requires": { + "pinkie-promise": "2.0.1" + } + }, + "path-is-absolute": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", + "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=" + }, + "path-parse": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.5.tgz", + "integrity": "sha1-PBrfhx6pzWyUMbbqK9dKD/BVxME=" + }, + "path-platform": { + "version": "0.11.15", + "resolved": "https://registry.npmjs.org/path-platform/-/path-platform-0.11.15.tgz", + "integrity": "sha1-6GQhf3TDaFDwhSt43Hv31KVyG/I=" + }, + "path-type": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/path-type/-/path-type-1.1.0.tgz", + "integrity": "sha1-WcRPfuSR2nBNpBXaWkBwuk+P5EE=", + "requires": { + "graceful-fs": "4.1.11", + "pify": "2.3.0", + "pinkie-promise": "2.0.1" + } + }, + "pbkdf2": { + "version": "3.0.14", + "resolved": "https://registry.npmjs.org/pbkdf2/-/pbkdf2-3.0.14.tgz", + "integrity": "sha512-gjsZW9O34fm0R7PaLHRJmLLVfSoesxztjPjE9o6R+qtVJij90ltg1joIovN9GKrRW3t1PzhDDG3UMEMFfZ+1wA==", + "requires": { + "create-hash": "1.1.3", + "create-hmac": "1.1.6", + "ripemd160": "2.0.1", + "safe-buffer": "5.1.1", + "sha.js": "2.4.9" + } + }, + "peer-id": { + "version": "0.10.2", + "resolved": "https://registry.npmjs.org/peer-id/-/peer-id-0.10.2.tgz", + "integrity": "sha512-E5uxAAhbLylyNE2FNWykyGqsRoiOOfprFOkZfCO7yTBFIJc2Gq+l6XKBeyWTQKR/eUizHbzZgexqEDcqFw84iw==", + "requires": { + "async": "2.6.0", + "libp2p-crypto": "0.10.3", + "lodash": "4.17.4", + "multihashes": "0.4.12" + } + }, + "peer-info": { + "version": "0.11.1", + "resolved": "https://registry.npmjs.org/peer-info/-/peer-info-0.11.1.tgz", + "integrity": "sha512-CSkBYu6gkEGRCbO7hS4S/drlniMxaZ/oAC7s0XzFDzNB/fTk5pQrgpn261IP4mJCn63leI4+Nl7R2NJecS47QQ==", + "requires": { + "lodash.uniqby": "4.7.0", + "multiaddr": "3.0.1", + "peer-id": "0.10.2" + } + }, + "pem-jwk": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/pem-jwk/-/pem-jwk-1.5.1.tgz", + "integrity": "sha1-eoY3/S9nqCflfAxC4cI8P9Us+wE=", + "requires": { + "asn1.js": "1.0.3" + }, + "dependencies": { + "asn1.js": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/asn1.js/-/asn1.js-1.0.3.tgz", + "integrity": "sha1-KBuj7B8kSP52X5Kk7s+IP+E2S1Q=", + "requires": { + "bn.js": "1.3.0", + "inherits": "2.0.3", + "minimalistic-assert": "1.0.0" + } + }, + "bn.js": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-1.3.0.tgz", + "integrity": "sha1-DbTL+W+PI7dC9by50ap6mZSgXoM=", + "optional": true + } + } + }, + "pify": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", + "integrity": "sha1-7RQaasBDqEnqWISY59yosVMw6Qw=" + }, + "pinkie": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/pinkie/-/pinkie-2.0.4.tgz", + "integrity": "sha1-clVrgM+g1IqXToDnckjoDtT3+HA=" + }, + "pinkie-promise": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/pinkie-promise/-/pinkie-promise-2.0.1.tgz", + "integrity": "sha1-ITXW36ejWMBprJsXh3YogihFD/o=", + "requires": { + "pinkie": "2.0.4" + } + }, + "prebuild-install": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/prebuild-install/-/prebuild-install-2.3.0.tgz", + "integrity": "sha512-gzjq2oHB8oMbzJSsSh9MQ64zrXZGt092/uT4TLZlz2qnrPxpWqp4vYB7LZrDxnlxf5RfbCjkgDI/z0EIVuYzAw==", + "requires": { + "expand-template": "1.1.0", + "github-from-package": "0.0.0", + "minimist": "1.2.0", + "mkdirp": "0.5.1", + "node-abi": "2.1.2", + "noop-logger": "0.1.1", + "npmlog": "4.1.2", + "os-homedir": "1.0.2", + "pump": "1.0.2", + "rc": "1.2.2", + "simple-get": "1.4.3", + "tar-fs": "1.16.0", + "tunnel-agent": "0.6.0", + "xtend": "4.0.1" + }, + "dependencies": { + "minimist": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz", + "integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ=" + } + } + }, + "prepend-http": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/prepend-http/-/prepend-http-1.0.4.tgz", + "integrity": "sha1-1PRWKwzjaW5BrFLQ4ALlemNdxtw=" + }, + "private": { + "version": "0.1.8", + "resolved": "https://registry.npmjs.org/private/-/private-0.1.8.tgz", + "integrity": "sha512-VvivMrbvd2nKkiG38qjULzlc+4Vx4wm/whI9pQD35YrARNnhxeiRktSOhSukRLFNlzg6Br/cJPet5J/u19r/mg==" + }, + "process": { + "version": "0.11.10", + "resolved": "https://registry.npmjs.org/process/-/process-0.11.10.tgz", + "integrity": "sha1-czIwDoQBYb2j5podHZGn1LwW8YI=" + }, + "process-nextick-args": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-1.0.7.tgz", + "integrity": "sha1-FQ4gt1ZZCtP5EJPyWk8q2L/zC6M=" + }, + "promise": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/promise/-/promise-1.3.0.tgz", + "integrity": "sha1-5cyaTIJ45GZP/twBx9qEhCsEAXU=", + "requires": { + "is-promise": "1.0.1" + } + }, + "promisify-es6": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/promisify-es6/-/promisify-es6-1.0.3.tgz", + "integrity": "sha512-N9iVG+CGJsI4b4ZGazjwLnxErD2d9Pe4DPvvXSxYA9tFNu8ymXME4Qs5HIQ0LMJpNM7zj+m0NlNnNeqFpKzqnA==" + }, + "protocol-buffers-schema": { + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/protocol-buffers-schema/-/protocol-buffers-schema-3.3.2.tgz", + "integrity": "sha512-Xdayp8sB/mU+sUV4G7ws8xtYMGdQnxbeIfLjyO9TZZRJdztBGhlmbI5x1qcY4TG5hBkIKGnc28i7nXxaugu88w==" + }, + "protons": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/protons/-/protons-1.0.0.tgz", + "integrity": "sha512-n+FhiYi0NMM3A84BeeD4tQ878F6qZnbaoBiO4GjIIzqyd4p5SaGiGwduPbtKeVMrNFuzIuh6jEA7vmw9sExcpQ==", + "requires": { + "brfs": "1.4.3", + "protocol-buffers-schema": "3.3.2", + "safe-buffer": "5.1.1", + "signed-varint": "2.0.1", + "varint": "5.0.0" + } + }, + "pseudomap": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/pseudomap/-/pseudomap-1.0.2.tgz", + "integrity": "sha1-8FKijacOYYkX7wqKw0wa5aaChrM=" + }, + "public-encrypt": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/public-encrypt/-/public-encrypt-4.0.0.tgz", + "integrity": "sha1-OfaZ86RlYN1eusvKaTyvfGXBjMY=", + "requires": { + "bn.js": "4.11.8", + "browserify-rsa": "4.0.1", + "create-hash": "1.1.3", + "parse-asn1": "5.1.0", + "randombytes": "2.0.5" + } + }, + "public-ip": { + "version": "2.3.5", + "resolved": "https://registry.npmjs.org/public-ip/-/public-ip-2.3.5.tgz", + "integrity": "sha1-fXhHYliBV2unofpBCwl43yOb33U=", + "requires": { + "dns-socket": "1.6.2", + "got": "6.7.1", + "is-ip": "2.0.0", + "pify": "2.3.0" + } + }, + "pull-stream": { + "version": "3.6.1", + "resolved": "https://registry.npmjs.org/pull-stream/-/pull-stream-3.6.1.tgz", + "integrity": "sha1-xcKuSlEkbv7rzGXAQSo9clqSzgA=" + }, + "pull-traverse": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/pull-traverse/-/pull-traverse-1.0.3.tgz", + "integrity": "sha1-dPtde+f6a9enjpeTPhmbeUWGaTg=" + }, + "pump": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/pump/-/pump-1.0.2.tgz", + "integrity": "sha1-Oz7mUS+U8OV1U4wXmV+fFpkKXVE=", + "requires": { + "end-of-stream": "1.4.0", + "once": "1.4.0" + } + }, + "punycode": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-1.4.1.tgz", + "integrity": "sha1-wNWmOycYgArY4esPpSachN1BhF4=" + }, + "qs": { + "version": "6.5.1", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.5.1.tgz", + "integrity": "sha512-eRzhrN1WSINYCDCbrz796z37LOe3m5tmW7RQf6oBntukAG1nmovJvhnwHHRMAfeoItc1m2Hk02WER2aQ/iqs+A==" + }, + "querystring": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/querystring/-/querystring-0.2.0.tgz", + "integrity": "sha1-sgmEkgO7Jd+CDadW50cAWHhSFiA=" + }, + "querystring-es3": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/querystring-es3/-/querystring-es3-0.2.1.tgz", + "integrity": "sha1-nsYfeQSYdXB9aUFFlv2Qek1xHnM=" + }, + "quote-stream": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/quote-stream/-/quote-stream-1.0.2.tgz", + "integrity": "sha1-hJY/jJwmuULhU/7rU6rnRlK34LI=", + "requires": { + "buffer-equal": "0.0.1", + "minimist": "1.2.0", + "through2": "2.0.3" + }, + "dependencies": { + "minimist": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz", + "integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ=" + } + } + }, + "randombytes": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.0.5.tgz", + "integrity": "sha512-8T7Zn1AhMsQ/HI1SjcCfT/t4ii3eAqco3yOcSzS4mozsOz69lHLsoMXmF9nZgnFanYscnSlUSgs8uZyKzpE6kg==", + "requires": { + "safe-buffer": "5.1.1" + } + }, + "randomfill": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/randomfill/-/randomfill-1.0.3.tgz", + "integrity": "sha512-YL6GrhrWoic0Eq8rXVbMptH7dAxCs0J+mh5Y0euNekPPYaxEmdVGim6GdoxoRzKW2yJoU8tueifS7mYxvcFDEQ==", + "requires": { + "randombytes": "2.0.5", + "safe-buffer": "5.1.1" + } + }, + "rc": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/rc/-/rc-1.2.2.tgz", + "integrity": "sha1-2M6ctX6NZNnHut2YdsfDTL48cHc=", + "requires": { + "deep-extend": "0.4.2", + "ini": "1.3.4", + "minimist": "1.2.0", + "strip-json-comments": "2.0.1" + }, + "dependencies": { + "minimist": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz", + "integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ=" + } + } + }, + "read-only-stream": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/read-only-stream/-/read-only-stream-2.0.0.tgz", + "integrity": "sha1-JyT9aoET1zdkrCiNQ4YnDB2/F/A=", + "requires": { + "readable-stream": "2.3.3" + } + }, + "read-pkg": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-1.1.0.tgz", + "integrity": "sha1-9f+qXs0pyzHAR0vKfXVra7KePyg=", + "requires": { + "load-json-file": "1.1.0", + "normalize-package-data": "2.4.0", + "path-type": "1.1.0" + } + }, + "read-pkg-up": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/read-pkg-up/-/read-pkg-up-1.0.1.tgz", + "integrity": "sha1-nWPBMnbAZZGNV/ACpX9AobZD+wI=", + "requires": { + "find-up": "1.1.2", + "read-pkg": "1.1.0" + } + }, + "readable-stream": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.3.tgz", + "integrity": "sha512-m+qzzcn7KUxEmd1gMbchF+Y2eIUbieUaxkWtptyHywrX0rE8QEYqPC07Vuy4Wm32/xE16NcdBctb8S0Xe/5IeQ==", + "requires": { + "core-util-is": "1.0.2", + "inherits": "2.0.3", + "isarray": "1.0.0", + "process-nextick-args": "1.0.7", + "safe-buffer": "5.1.1", + "string_decoder": "1.0.3", + "util-deprecate": "1.0.2" + } + }, + "readline-sync": { + "version": "1.4.7", + "resolved": "https://registry.npmjs.org/readline-sync/-/readline-sync-1.4.7.tgz", + "integrity": "sha1-ABv91MBhEMPAhMY798alYCIhPzA=" + }, + "regenerate": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/regenerate/-/regenerate-1.3.3.tgz", + "integrity": "sha512-jVpo1GadrDAK59t/0jRx5VxYWQEDkkEKi6+HjE3joFVLfDOh9Xrdh0dF1eSq+BI/SwvTQ44gSscJ8N5zYL61sg==" + }, + "regenerator-runtime": { + "version": "0.11.0", + "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.11.0.tgz", + "integrity": "sha512-/aA0kLeRb5N9K0d4fw7ooEbI+xDe+DKD499EQqygGqeS8N3xto15p09uY2xj7ixP81sNPXvRLnAQIqdVStgb1A==" + }, + "regenerator-transform": { + "version": "0.10.1", + "resolved": "https://registry.npmjs.org/regenerator-transform/-/regenerator-transform-0.10.1.tgz", + "integrity": "sha512-PJepbvDbuK1xgIgnau7Y90cwaAmO/LCLMI2mPvaXq2heGMR3aWW5/BQvYrhJ8jgmQjXewXvBjzfqKcVOmhjZ6Q==", + "requires": { + "babel-runtime": "6.26.0", + "babel-types": "6.26.0", + "private": "0.1.8" + } + }, + "regexpu-core": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/regexpu-core/-/regexpu-core-2.0.0.tgz", + "integrity": "sha1-SdA4g3uNz4v6W5pCE5k45uoq4kA=", + "requires": { + "regenerate": "1.3.3", + "regjsgen": "0.2.0", + "regjsparser": "0.1.5" + } + }, + "regjsgen": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/regjsgen/-/regjsgen-0.2.0.tgz", + "integrity": "sha1-bAFq3qxVT3WCP+N6wFuS1aTtsfc=" + }, + "regjsparser": { + "version": "0.1.5", + "resolved": "https://registry.npmjs.org/regjsparser/-/regjsparser-0.1.5.tgz", + "integrity": "sha1-fuj4Tcb6eS0/0K4ijSS9lJ6tIFw=", + "requires": { + "jsesc": "0.5.0" + } + }, + "repeating": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/repeating/-/repeating-2.0.1.tgz", + "integrity": "sha1-UhTFOpJtNVJwdSf7q0FdvAjQbdo=", + "requires": { + "is-finite": "1.0.2" + } + }, + "require-directory": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", + "integrity": "sha1-jGStX9MNqxyXbiNE/+f3kqam30I=" + }, + "require-main-filename": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/require-main-filename/-/require-main-filename-1.0.1.tgz", + "integrity": "sha1-l/cXtp1IeE9fUmpsWqj/3aBVpNE=" + }, + "resolve": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.5.0.tgz", + "integrity": "sha512-hgoSGrc3pjzAPHNBg+KnFcK2HwlHTs/YrAGUr6qgTVUZmXv1UEXXl0bZNBKMA9fud6lRYFdPGz0xXxycPzmmiw==", + "requires": { + "path-parse": "1.0.5" + } + }, + "ripemd160": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/ripemd160/-/ripemd160-2.0.1.tgz", + "integrity": "sha1-D0WEKVxTo2KK9+bXmsohzlfRxuc=", + "requires": { + "hash-base": "2.0.2", + "inherits": "2.0.3" + } + }, + "rsa-pem-to-jwk": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/rsa-pem-to-jwk/-/rsa-pem-to-jwk-1.1.3.tgz", + "integrity": "sha1-JF52vbfnI0z+58oDLTG1TDj6uY4=", + "requires": { + "object-assign": "2.1.1", + "rsa-unpack": "0.0.6" + }, + "dependencies": { + "object-assign": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-2.1.1.tgz", + "integrity": "sha1-Q8NuXVaf+OSBbE76i+AtJpZ8GKo=" + } + } + }, + "rsa-unpack": { + "version": "0.0.6", + "resolved": "https://registry.npmjs.org/rsa-unpack/-/rsa-unpack-0.0.6.tgz", + "integrity": "sha1-9Q69VqYoN45jHylxYQJs6atO3bo=", + "requires": { + "optimist": "0.3.7" + } + }, + "safe-buffer": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.1.tgz", + "integrity": "sha512-kKvNJn6Mm93gAczWVJg7wH+wGYWNrDHdWvpUmHyEsgCtIwwo3bqPtV4tR5tuPaUhTOo/kvhVwd8XwwOllGYkbg==" + }, + "sandwich-stream": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/sandwich-stream/-/sandwich-stream-1.0.0.tgz", + "integrity": "sha1-eDDkV5e1kzKH8fmyj4cZB0ViYvI=" + }, + "secp256k1": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/secp256k1/-/secp256k1-3.3.1.tgz", + "integrity": "sha512-lygjgfjzjBHblEDDkppUF5KK1EeVk6P/Dv2MsJZpYIR3vW5TKFRexOFkf0hHy9J5YxEpjQZ6x98Y3XQpMQO/vA==", + "requires": { + "bindings": "1.3.0", + "bip66": "1.1.5", + "bn.js": "4.11.8", + "create-hash": "1.1.3", + "drbg.js": "1.0.1", + "elliptic": "6.4.0", + "nan": "2.7.0", + "prebuild-install": "2.3.0", + "safe-buffer": "5.1.1" + } + }, + "semver": { + "version": "5.4.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.4.1.tgz", + "integrity": "sha512-WfG/X9+oATh81XtllIo/I8gOiY9EXRdv1cQdyykeXK17YcUW3EXUAi2To4pcH6nZtJPr7ZOpM5OMyWJZm+8Rsg==" + }, + "set-blocking": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz", + "integrity": "sha1-BF+XgtARrppoA93TgrJDkrPYkPc=" + }, + "sha.js": { + "version": "2.4.9", + "resolved": "https://registry.npmjs.org/sha.js/-/sha.js-2.4.9.tgz", + "integrity": "sha512-G8zektVqbiPHrylgew9Zg1VRB1L/DtXNUVAM6q4QLy8NE3qtHlFXTf8VLL4k1Yl6c7NMjtZUTdXV+X44nFaT6A==", + "requires": { + "inherits": "2.0.3", + "safe-buffer": "5.1.1" + } + }, + "shallow-copy": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/shallow-copy/-/shallow-copy-0.0.1.tgz", + "integrity": "sha1-QV9CcC1z2BAzApLMXuhurhoRoXA=" + }, + "shasum": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/shasum/-/shasum-1.0.2.tgz", + "integrity": "sha1-5wEjENj0F/TetXEhUOVni4euVl8=", + "requires": { + "json-stable-stringify": "0.0.1", + "sha.js": "2.4.9" + } + }, + "shell-quote": { + "version": "1.6.1", + "resolved": "https://registry.npmjs.org/shell-quote/-/shell-quote-1.6.1.tgz", + "integrity": "sha1-9HgZSczkAmlxJ0MOo7PFR29IF2c=", + "requires": { + "array-filter": "0.0.1", + "array-map": "0.0.0", + "array-reduce": "0.0.0", + "jsonify": "0.0.0" + } + }, + "signal-exit": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.2.tgz", + "integrity": "sha1-tf3AjxKH6hF4Yo5BXiUTK3NkbG0=" + }, + "signed-varint": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/signed-varint/-/signed-varint-2.0.1.tgz", + "integrity": "sha1-UKmYnafJjCxh2tEZvJdHDvhSgSk=", + "requires": { + "varint": "5.0.0" + } + }, + "simple-get": { + "version": "1.4.3", + "resolved": "https://registry.npmjs.org/simple-get/-/simple-get-1.4.3.tgz", + "integrity": "sha1-6XVe2kB+ltpAxeUVjJ6jezO+y+s=", + "requires": { + "once": "1.4.0", + "unzip-response": "1.0.2", + "xtend": "4.0.1" + } + }, + "slash": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/slash/-/slash-1.0.0.tgz", + "integrity": "sha1-xB8vbDn8FtHNF61LXYlhFK5HDVU=" + }, + "source-map": { + "version": "0.5.7", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", + "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=" + }, + "source-map-support": { + "version": "0.4.18", + "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.4.18.tgz", + "integrity": "sha512-try0/JqxPLF9nOjvSta7tVondkP5dwgyLDjVoyMDlmjugT2lRZ1OfsrYTkCd2hkDnJTKRbO/Rl3orm8vlsUzbA==", + "requires": { + "source-map": "0.5.7" + } + }, + "spdx-correct": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/spdx-correct/-/spdx-correct-1.0.2.tgz", + "integrity": "sha1-SzBz2TP/UfORLwOsVRlJikFQ20A=", + "requires": { + "spdx-license-ids": "1.2.2" + } + }, + "spdx-expression-parse": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/spdx-expression-parse/-/spdx-expression-parse-1.0.4.tgz", + "integrity": "sha1-m98vIOH0DtRH++JzJmGR/O1RYmw=" + }, + "spdx-license-ids": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-1.2.2.tgz", + "integrity": "sha1-yd96NCRZSt5r0RkA1ZZpbcBrrFc=" + }, + "split2": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/split2/-/split2-2.2.0.tgz", + "integrity": "sha512-RAb22TG39LhI31MbreBgIuKiIKhVsawfTgEGqKHTK87aG+ul/PB8Sqoi3I7kVdRWiCfrKxK3uo4/YUkpNvhPbw==", + "requires": { + "through2": "2.0.3" + } + }, + "stable": { + "version": "0.1.6", + "resolved": "https://registry.npmjs.org/stable/-/stable-0.1.6.tgz", + "integrity": "sha1-kQ9dKu17Ugxud3SZwfMuE5/eyxA=" + }, + "static-eval": { + "version": "0.2.4", + "resolved": "https://registry.npmjs.org/static-eval/-/static-eval-0.2.4.tgz", + "integrity": "sha1-t9NNg4k3uWn5ZBygfUj47eJj6ns=", + "requires": { + "escodegen": "0.0.28" + }, + "dependencies": { + "escodegen": { + "version": "0.0.28", + "resolved": "https://registry.npmjs.org/escodegen/-/escodegen-0.0.28.tgz", + "integrity": "sha1-Dk/xcV8yh3XWyrUaxEpAbNer/9M=", + "requires": { + "esprima": "1.0.4", + "estraverse": "1.3.2", + "source-map": "0.5.7" + } + }, + "esprima": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/esprima/-/esprima-1.0.4.tgz", + "integrity": "sha1-n1V+CPw7TSbs6d00+Pv0drYlha0=" + }, + "estraverse": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-1.3.2.tgz", + "integrity": "sha1-N8K4k+8T1yPydth41g2FNRUqbEI=" + } + } + }, + "static-module": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/static-module/-/static-module-1.5.0.tgz", + "integrity": "sha1-J9qYg8QajNCSNvhC8MHrxu32PYY=", + "requires": { + "concat-stream": "1.6.0", + "duplexer2": "0.0.2", + "escodegen": "1.3.3", + "falafel": "2.1.0", + "has": "1.0.1", + "object-inspect": "0.4.0", + "quote-stream": "0.0.0", + "readable-stream": "1.0.34", + "shallow-copy": "0.0.1", + "static-eval": "0.2.4", + "through2": "0.4.2" + }, + "dependencies": { + "concat-stream": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/concat-stream/-/concat-stream-1.6.0.tgz", + "integrity": "sha1-CqxmL9Ur54lk1VMvaUeE5wEQrPc=", + "requires": { + "inherits": "2.0.3", + "readable-stream": "2.3.3", + "typedarray": "0.0.6" + }, + "dependencies": { + "readable-stream": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.3.tgz", + "integrity": "sha512-m+qzzcn7KUxEmd1gMbchF+Y2eIUbieUaxkWtptyHywrX0rE8QEYqPC07Vuy4Wm32/xE16NcdBctb8S0Xe/5IeQ==", + "requires": { + "core-util-is": "1.0.2", + "inherits": "2.0.3", + "isarray": "1.0.0", + "process-nextick-args": "1.0.7", + "safe-buffer": "5.1.1", + "string_decoder": "1.0.3", + "util-deprecate": "1.0.2" + } + } + } + }, + "duplexer2": { + "version": "0.0.2", + "resolved": "https://registry.npmjs.org/duplexer2/-/duplexer2-0.0.2.tgz", + "integrity": "sha1-xhTc9n4vsUmVqRcR5aYX6KYKMds=", + "requires": { + "readable-stream": "1.1.14" + }, + "dependencies": { + "isarray": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz", + "integrity": "sha1-ihis/Kmo9Bd+Cav8YDiTmwXR7t8=" + }, + "readable-stream": { + "version": "1.1.14", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-1.1.14.tgz", + "integrity": "sha1-fPTFTvZI44EwhMY23SB54WbAgdk=", + "requires": { + "core-util-is": "1.0.2", + "inherits": "2.0.3", + "isarray": "0.0.1", + "string_decoder": "0.10.31" + } + }, + "string_decoder": { + "version": "0.10.31", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-0.10.31.tgz", + "integrity": "sha1-YuIDvEF2bGwoyfyEMB2rHFMQ+pQ=" + } + } + }, + "object-keys": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-0.4.0.tgz", + "integrity": "sha1-KKaq50KN0sOpLz2V8hM13SBOAzY=" + }, + "quote-stream": { + "version": "0.0.0", + "resolved": "https://registry.npmjs.org/quote-stream/-/quote-stream-0.0.0.tgz", + "integrity": "sha1-zeKelMQJsW4Z3HCYuJtmWPlyHTs=", + "requires": { + "minimist": "0.0.8", + "through2": "0.4.2" + } + }, + "readable-stream": { + "version": "1.0.34", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-1.0.34.tgz", + "integrity": "sha1-Elgg40vIQtLyqq+v5MKRbuMsFXw=", + "requires": { + "core-util-is": "1.0.2", + "inherits": "2.0.3", + "isarray": "0.0.1", + "string_decoder": "0.10.31" + }, + "dependencies": { + "isarray": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz", + "integrity": "sha1-ihis/Kmo9Bd+Cav8YDiTmwXR7t8=" + }, + "string_decoder": { + "version": "0.10.31", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-0.10.31.tgz", + "integrity": "sha1-YuIDvEF2bGwoyfyEMB2rHFMQ+pQ=" + } + } + }, + "through2": { + "version": "0.4.2", + "resolved": "https://registry.npmjs.org/through2/-/through2-0.4.2.tgz", + "integrity": "sha1-2/WGYDEVHsg1K7bE22SiKSqEC5s=", + "requires": { + "readable-stream": "1.0.34", + "xtend": "2.1.2" + } + }, + "xtend": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/xtend/-/xtend-2.1.2.tgz", + "integrity": "sha1-bv7MKk2tjmlixJAbM3znuoe10os=", + "requires": { + "object-keys": "0.4.0" + } + } + } + }, + "stream-browserify": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/stream-browserify/-/stream-browserify-2.0.1.tgz", + "integrity": "sha1-ZiZu5fm9uZQKTkUUyvtDu3Hlyds=", + "requires": { + "inherits": "2.0.3", + "readable-stream": "2.3.3" + } + }, + "stream-buffers": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/stream-buffers/-/stream-buffers-3.0.1.tgz", + "integrity": "sha1-aKOMX6re3tef95mI02jj+xMl7wY=", + "dev": true + }, + "stream-combiner2": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/stream-combiner2/-/stream-combiner2-1.1.1.tgz", + "integrity": "sha1-+02KFCDqNidk4hrUeAOXvry0HL4=", + "requires": { + "duplexer2": "0.1.4", + "readable-stream": "2.3.3" + } + }, + "stream-http": { + "version": "2.7.2", + "resolved": "https://registry.npmjs.org/stream-http/-/stream-http-2.7.2.tgz", + "integrity": "sha512-c0yTD2rbQzXtSsFSVhtpvY/vS6u066PcXOX9kBB3mSO76RiUQzL340uJkGBWnlBg4/HZzqiUXtaVA7wcRcJgEw==", + "requires": { + "builtin-status-codes": "3.0.0", + "inherits": "2.0.3", + "readable-stream": "2.3.3", + "to-arraybuffer": "1.0.1", + "xtend": "4.0.1" + } + }, + "stream-splicer": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/stream-splicer/-/stream-splicer-2.0.0.tgz", + "integrity": "sha1-G2O+Q4oTPktnHMGTUZdgAXWRDYM=", + "requires": { + "inherits": "2.0.3", + "readable-stream": "2.3.3" + } + }, + "streamifier": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/streamifier/-/streamifier-0.1.1.tgz", + "integrity": "sha1-l+mNj6TRBdYqJpHR3AfoINuN/E8=" + }, + "string-width": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-1.0.2.tgz", + "integrity": "sha1-EYvfW4zcUaKn5w0hHgfisLmxB9M=", + "requires": { + "code-point-at": "1.1.0", + "is-fullwidth-code-point": "1.0.0", + "strip-ansi": "3.0.1" + } + }, + "string_decoder": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.0.3.tgz", + "integrity": "sha512-4AH6Z5fzNNBcH+6XDMfA/BTt87skxqJlO0lAh3Dker5zThcAxG6mKz+iGu308UKoPPQ8Dcqx/4JhujzltRa+hQ==", + "requires": { + "safe-buffer": "5.1.1" + } + }, + "strip-ansi": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", + "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=", + "requires": { + "ansi-regex": "2.1.1" + } + }, + "strip-bom": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-2.0.0.tgz", + "integrity": "sha1-YhmoVhZSBJHzV4i9vxRHqZx+aw4=", + "requires": { + "is-utf8": "0.2.1" + } + }, + "strip-json-comments": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-2.0.1.tgz", + "integrity": "sha1-PFMZQukIwml8DsNEhYwobHygpgo=" + }, + "subarg": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/subarg/-/subarg-1.0.0.tgz", + "integrity": "sha1-9izxdYHplrSPyWVpn1TAauJouNI=", + "requires": { + "minimist": "1.2.0" + }, + "dependencies": { + "minimist": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz", + "integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ=" + } + } + }, + "supports-color": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz", + "integrity": "sha1-U10EXOa2Nj+kARcIRimZXp3zJMc=" + }, + "syntax-error": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/syntax-error/-/syntax-error-1.3.0.tgz", + "integrity": "sha1-HtkmbE1AvnXcVb+bsct3Biu5bKE=", + "requires": { + "acorn": "4.0.13" + } + }, + "tar-fs": { + "version": "1.16.0", + "resolved": "https://registry.npmjs.org/tar-fs/-/tar-fs-1.16.0.tgz", + "integrity": "sha512-I9rb6v7mjWLtOfCau9eH5L7sLJyU2BnxtEZRQ5Mt+eRKmf1F0ohXmT/Jc3fr52kDvjJ/HV5MH3soQfPL5bQ0Yg==", + "requires": { + "chownr": "1.0.1", + "mkdirp": "0.5.1", + "pump": "1.0.2", + "tar-stream": "1.5.5" + } + }, + "tar-stream": { + "version": "1.5.5", + "resolved": "https://registry.npmjs.org/tar-stream/-/tar-stream-1.5.5.tgz", + "integrity": "sha512-mQdgLPc/Vjfr3VWqWbfxW8yQNiJCbAZ+Gf6GDu1Cy0bdb33ofyiNGBtAY96jHFhDuivCwgW1H9DgTON+INiXgg==", + "requires": { + "bl": "1.2.1", + "end-of-stream": "1.4.0", + "readable-stream": "2.3.3", + "xtend": "4.0.1" + } + }, + "through": { + "version": "2.3.8", + "resolved": "https://registry.npmjs.org/through/-/through-2.3.8.tgz", + "integrity": "sha1-DdTJ/6q8NXlgsbckEV1+Doai4fU=" + }, + "through2": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/through2/-/through2-2.0.3.tgz", + "integrity": "sha1-AARWmzfHx0ujnEPzzteNGtlBQL4=", + "requires": { + "readable-stream": "2.3.3", + "xtend": "4.0.1" + } + }, + "timed-out": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/timed-out/-/timed-out-4.0.1.tgz", + "integrity": "sha1-8y6srFoXW+ol1/q1Zas+2HQe9W8=" + }, + "timers-browserify": { + "version": "1.4.2", + "resolved": "https://registry.npmjs.org/timers-browserify/-/timers-browserify-1.4.2.tgz", + "integrity": "sha1-ycWLV1voQHN1y14kYtrO50NZ9B0=", + "requires": { + "process": "0.11.10" + } + }, + "tmatch": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/tmatch/-/tmatch-2.0.1.tgz", + "integrity": "sha1-DFYkbzPzDaG409colauvFmYPOM8=" + }, + "to-arraybuffer": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/to-arraybuffer/-/to-arraybuffer-1.0.1.tgz", + "integrity": "sha1-fSKbH8xjfkZsoIEYCDanqr/4P0M=" + }, + "to-fast-properties": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-1.0.3.tgz", + "integrity": "sha1-uDVx+k2MJbguIxsG46MFXeTKGkc=" + }, + "trim-right": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/trim-right/-/trim-right-1.0.1.tgz", + "integrity": "sha1-yy4SAwZ+DI3h9hQJS5/kVwTqYAM=" + }, + "tslib": { + "version": "1.8.0", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.8.0.tgz", + "integrity": "sha512-ymKWWZJST0/CkgduC2qkzjMOWr4bouhuURNXCn/inEX0L57BnRG6FhX76o7FOnsjHazCjfU2LKeSrlS2sIKQJg==" + }, + "tty-browserify": { + "version": "0.0.0", + "resolved": "https://registry.npmjs.org/tty-browserify/-/tty-browserify-0.0.0.tgz", + "integrity": "sha1-oVe6QC2iTpv5V/mqadUk7tQpAaY=" + }, + "tunnel-agent": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.6.0.tgz", + "integrity": "sha1-J6XeoGs2sEoKmWZ3SykIaPD8QP0=", + "requires": { + "safe-buffer": "5.1.1" + } + }, + "tweetnacl": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/tweetnacl/-/tweetnacl-1.0.0.tgz", + "integrity": "sha1-cT2LgY2kIGh0C/aDhtBHnmb8ins=" + }, + "typedarray": { + "version": "0.0.6", + "resolved": "https://registry.npmjs.org/typedarray/-/typedarray-0.0.6.tgz", + "integrity": "sha1-hnrHTjhkGHsdPUfZlqeOxciDB3c=" + }, + "umd": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/umd/-/umd-3.0.1.tgz", + "integrity": "sha1-iuVW4RAR9jwllnCKiDclnwGz1g4=" + }, + "unzip-response": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/unzip-response/-/unzip-response-1.0.2.tgz", + "integrity": "sha1-uYTwh3/AqJwsdzzB73tbIytbBv4=" + }, + "url": { + "version": "0.11.0", + "resolved": "https://registry.npmjs.org/url/-/url-0.11.0.tgz", + "integrity": "sha1-ODjpfPxgUh63PFJajlW/3Z4uKPE=", + "requires": { + "punycode": "1.3.2", + "querystring": "0.2.0" + }, + "dependencies": { + "punycode": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-1.3.2.tgz", + "integrity": "sha1-llOgNvt8HuQjQvIyXM7v6jkmxI0=" + } + } + }, + "url-parse-lax": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/url-parse-lax/-/url-parse-lax-1.0.0.tgz", + "integrity": "sha1-evjzA2Rem9eaJy56FKxovAYJ2nM=", + "requires": { + "prepend-http": "1.0.4" + } + }, + "util": { + "version": "0.10.3", + "resolved": "https://registry.npmjs.org/util/-/util-0.10.3.tgz", + "integrity": "sha1-evsa/lCAUkZInj23/g7TeTNqwPk=", + "requires": { + "inherits": "2.0.1" + }, + "dependencies": { + "inherits": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.1.tgz", + "integrity": "sha1-sX0I0ya0Qj5Wjv9xn5GwscvfafE=" + } + } + }, + "util-deprecate": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", + "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=" + }, + "validate-npm-package-license": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/validate-npm-package-license/-/validate-npm-package-license-3.0.1.tgz", + "integrity": "sha1-KAS6vnEq0zeUWaz74kdGqywwP7w=", + "requires": { + "spdx-correct": "1.0.2", + "spdx-expression-parse": "1.0.4" + } + }, + "varint": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/varint/-/varint-5.0.0.tgz", + "integrity": "sha1-2Ca4n3SQcy+rwMDtaT7Uddyynr8=" + }, + "vm-browserify": { + "version": "0.0.4", + "resolved": "https://registry.npmjs.org/vm-browserify/-/vm-browserify-0.0.4.tgz", + "integrity": "sha1-XX6kW7755Kb/ZflUOOCofDV9WnM=", + "requires": { + "indexof": "0.0.1" + } + }, + "webcrypto-core": { + "version": "0.1.17", + "resolved": "https://registry.npmjs.org/webcrypto-core/-/webcrypto-core-0.1.17.tgz", + "integrity": "sha512-pyyNqOmUlsvOZVff6GUbZSzL8WDDuyFOrx8JWeUYz0nJ3rwfQbARwDMePuBV65dF7FkUS4ECGzNS6PTue98gLw==", + "requires": { + "tslib": "1.8.0" + } + }, + "webcrypto-crypt": { + "version": "0.1.15", + "resolved": "https://registry.npmjs.org/webcrypto-crypt/-/webcrypto-crypt-0.1.15.tgz", + "integrity": "sha512-ecZvHvfxHF5SQhJyBIO+oggpIuzkJN0yFT3MjX6RAMUUKbqtV19X9mv5HDagjVw8mOJ61DX6/Kbmd5SU4sOkqw==", + "requires": { + "async": "2.6.0", + "babel-preset-es2015": "6.24.1", + "babel-register": "6.26.0", + "babelify": "7.3.0", + "binary-split": "1.0.3", + "bindexof": "1.0.1", + "blob-to-buffer": "1.2.6", + "browserify": "14.5.0", + "chop": "0.0.1", + "expect": "1.20.2", + "fstat-mode": "0.0.1", + "mkdirp": "0.5.1", + "node-webcrypto-ossl": "1.0.31", + "npm": "4.6.1", + "readline-sync": "1.4.7", + "through2": "2.0.3", + "yargs": "7.1.0" + } + }, + "webcrypto-shim": { + "version": "github:dignifiedquire/webcrypto-shim#190bc9ec341375df6025b17ae12ddb2428ea49c8" + }, + "which-module": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/which-module/-/which-module-1.0.0.tgz", + "integrity": "sha1-u6Y8qGGUiZT/MHc2CJ47lgJsKk8=" + }, + "wide-align": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/wide-align/-/wide-align-1.1.2.tgz", + "integrity": "sha512-ijDLlyQ7s6x1JgCLur53osjm/UXUYD9+0PbYKrBsYisYXzCxN+HC3mYDNy/dWdmf3AwqwU3CXwDCvsNgGK1S0w==", + "requires": { + "string-width": "1.0.2" + } + }, + "wordwrap": { + "version": "0.0.3", + "resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-0.0.3.tgz", + "integrity": "sha1-o9XabNXAvAAI03I0u68b7WMFkQc=" + }, + "wrap-ansi": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-2.1.0.tgz", + "integrity": "sha1-2Pw9KE3QV5T+hJc8rs3Rz4JP3YU=", + "requires": { + "string-width": "1.0.2", + "strip-ansi": "3.0.1" + } + }, + "wrappy": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", + "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=" + }, + "xtend": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.1.tgz", + "integrity": "sha1-pcbVMr5lbiPbgg77lDofBJmNY68=" + }, + "y18n": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/y18n/-/y18n-3.2.1.tgz", + "integrity": "sha1-bRX7qITAhnnA136I53WegR4H+kE=" + }, + "yallist": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-2.1.2.tgz", + "integrity": "sha1-HBH5IY8HYImkfdUS+TxmmaaoHVI=" + }, + "yargs": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-7.1.0.tgz", + "integrity": "sha1-a6MY6xaWFyf10oT46gA+jWFU0Mg=", + "requires": { + "camelcase": "3.0.0", + "cliui": "3.2.0", + "decamelize": "1.2.0", + "get-caller-file": "1.0.2", + "os-locale": "1.4.0", + "read-pkg-up": "1.0.1", + "require-directory": "2.1.1", + "require-main-filename": "1.0.1", + "set-blocking": "2.0.0", + "string-width": "1.0.2", + "which-module": "1.0.0", + "y18n": "3.2.1", + "yargs-parser": "5.0.0" + } + }, + "yargs-parser": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-5.0.0.tgz", + "integrity": "sha1-J17PDX/+Bcd+ZOfIbkzZS/DhIoo=", + "requires": { + "camelcase": "3.0.0" + } + } + } +} diff --git a/package.json b/package.json new file mode 100644 index 0000000..f1511af --- /dev/null +++ b/package.json @@ -0,0 +1,54 @@ +{ + "name": "ipfsecret", + "repository": { + "type": "git", + "url": "https://github.com/c2fo-lab/ipfsecret.git" + }, + "license": "MIT", + "version": "0.1.0", + "author": "C2FO Innovation Lab", + "bin": { + "ipfsecret": "./bin/ipfsecret.js" + }, + "description": "Secret key encryption for IPFS files", + "homepage": "https://c2folab.com", + "dependencies": { + "adm-zip": "^0.4.7", + "async": "^2.2.0", + "babel-preset-es2015": "^6.24.1", + "babel-register": "^6.24.1", + "babelify": "^7.3.0", + "binary-split": "^1.0.3", + "blob-to-buffer": "^1.2.6", + "browserify": "latest", + "chop": "0.0.1", + "detect-browser": "^2.0.0", + "file-saver": "^1.3.3", + "he": "^1.1.1", + "install": "^0.10.1", + "ipfs-api": "^14.0.4", + "is-online": "^7.0.0", + "milligram": "^1.3.0", + "mkdirp": "^0.5.1", + "node-dir": "^0.1.17", + "normalize.css": "^7.0.0", + "npm": "^4.6.1", + "to-arraybuffer": "^1.0.1", + "webcrypto-crypt": "^0.1.15" + }, + "devDependencies": { + "expect": "^1.20.2", + "mocha": "^3.2.0", + "stream-buffers": "^3.0.1" + }, + "engines": { + "node": "8", + "npm": "4.5" + }, + "main": "index.js", + "scripts": { + "clean": "rm -rf node_modules assets/fonts/* dist examples assets/js/sha512.txt", + "postinstall": "./bin/install.sh", + "test": "./node_modules/.bin/mocha --timeout 10000 --reporter spec" + } +} diff --git a/test/.wcryptpass b/test/.wcryptpass new file mode 100644 index 0000000..fcddeba --- /dev/null +++ b/test/.wcryptpass @@ -0,0 +1 @@ +justtesting diff --git a/test/add-index.js b/test/add-index.js new file mode 100644 index 0000000..0028563 --- /dev/null +++ b/test/add-index.js @@ -0,0 +1,376 @@ +const bs58 = require('bs58'), + Config = require('../lib/config.json'), + expect = require('expect'), + path = require('path'), + fs = require('fs'), + util = require('util'), + readFile = util.promisify(fs.readFile), + ipfsAPI = require('ipfs-api'), + ipfs = ipfsAPI( + Config.ipfs.host, + Config.ipfs.port, + {protocol:Config.ipfs.proto} + ); + IPFSecret = require('../index.js'), + sBuff = require('stream-buffers'); + +process.env.IPFSECRET_ENV = 'test'; + +function checkCSS(data, done) { + expect(data.length).toEqual(5); + data.forEach(d => { + expect(d).toIncludeKey('path'); + expect(d).toIncludeKey('content'); + }); + expect(data[0].content.toString('utf8')).toMatch(/normalize.css v7.0.0/); + expect(data[1].content.toString('utf8')).toMatch(/Modal box Css/); + expect(data[2].content.toString('utf8')).toMatch(/roboto-300 - latin/); + expect(data[3].content.toString('utf8')).toMatch(/Milligram/); + expect(data[4].content.toString('utf8')).toMatch(/"mappings":"/); + expect(data[5]).toEqual(undefined); + done(); +} + +function checkEntryFormat(result, done) { + expect(result).toIncludeKey('path'); + expect(result).toIncludeKey('hash'); + expect(result).toIncludeKey('size'); + done(); +} + +function checkFonts(data, done) { + expect(data.length).toEqual(10); + data.forEach(d => { + expect(d).toIncludeKey('path'); + expect(d).toIncludeKey('content'); + expect(Buffer.isBuffer(d.content)).toExist(); + }); + expect(data[10]).toEqual(undefined); + done(); +} + +function checkIndexContent(ipfsecret, testPass, results, done) { + const subdir = Config.ipfs.mainSubdir.replace(/^\//, ''); + let hash = ''; + results.forEach(r => { + if (r.path === subdir + '/' + Config.ipfs.mainIndex) + hash = r.hash; + }); + ipfs.get(hash).then(stream => { + stream.on('data', obj => { + if (obj.content) { + const writeable = new sBuff.WritableStreamBuffer(), + docType = new RegExp('', 'g'), + dirTest = new RegExp('', 'g'); + writeable.on('finish', () => { + const results = writeable.getContents().toString('utf8'); + expect(results).toMatch(docType); + expect(results).toMatch(dirTest); + done(); + }); + obj.content.pipe(writeable); + obj.content.on('error', (err) => {done(err);}); + } + }); + }) + .catch(err => {done(err);}); +} + +function checkIndices(results, done) { + const subdir = Config.ipfs.mainSubdir.replace(/^\//, ''); + let expected = []; + results.forEach(r => { + if ( + (r.path === subdir + '/' + Config.ipfs.mainIndex) || + (r.path === subdir + '/test/' + Config.ipfs.mainIndex) + ) expected.push(r.path); + }); + expect(expected.length).toEqual(2); + done(); +} + +function checkJS(data, done) { + expect(data.length).toEqual(1); + expect(data[0]).toIncludeKey('path'); + expect(data[0]).toIncludeKey('content'); + expect(data[0].content).toMatch(/webcrypto-crypt/); + expect(data[0].content).toMatch(/"version": "0.1.12"/); + done(); +} + +function checkRelLinks(p, content, run, matched, done) { + const d = Config.ipfs.mainSubdir.replace(/^\//, ''), + r = new RegExp(d + '/'), + t = { + 'ipfsecret.html' : 'ipfsecret/st', + 'node_modules/ipfsecret.html' : '../ipfsecret', + 'node_modules/webcrypto-crypt/ipfsecret.html' : '../../ipfsec', + 'node_modules/webcrypto-crypt/examples/ipfsecret.html' : '../../../ipf', + 'node_modules/webcrypto-crypt/examples/browser/ipfsecret.html': '../../../../' + }; + if (content) { + const cssRegex = new RegExp(' { + if (stderr.match(/\[debug\] /)) + done(); + else + done(new Error('No stderr output detected.')); + }); + }); + +});
${ util.cfg.ipfs.ui.name }${ util.cfg.ipfs.ui.size }${ util.cfg.ipfs.ui.modified } 
\\[test\\]