├── .babelrc ├── .dockerignore ├── .editorconfig ├── .eslintignore ├── .eslintrc.js ├── .gitignore ├── .nvmrc ├── .travis.yml ├── CONTRIBUTING.md ├── Jenkinsfile ├── LICENSE ├── README.md ├── build ├── build.js ├── check-versions.js ├── dev-client.js ├── dev-server.js ├── utils.js ├── vue-loader.conf.js ├── webpack.base.conf.js ├── webpack.dev.conf.js ├── webpack.prod.conf.js └── webpack.test.conf.js ├── config ├── dev.env.js ├── index.js ├── prod.env.js └── test.env.js ├── dist └── .gitignore ├── dockerfiles ├── build.dockerfile ├── build.sh ├── deploy.staging.sh ├── files │ ├── certs.dev │ │ ├── cert.pem │ │ ├── dhparams.pem │ │ └── key.pem │ ├── configs │ │ ├── nginx-default │ │ └── nginx-default-ssl │ └── scripts │ │ ├── helpers │ │ ├── logger │ │ │ ├── index.js │ │ │ ├── selenium.js │ │ │ └── utils.js │ │ └── processes.js │ │ ├── inject_static_secrets │ │ ├── install_deps_debian.sh │ │ ├── node_setup.sh │ │ └── start-bridge-gui ├── push.sh └── serve.dockerfile ├── index.html ├── package-lock.json ├── package.json ├── src ├── App.vue ├── api │ ├── billing-client.js │ ├── bridge-client.js │ └── client.js ├── components │ ├── Message-Page.vue │ ├── Nav-Authentication.vue │ ├── Sj-Crypto-Payment-Btn.vue │ ├── Sj-Go-Back-Btn.vue │ ├── Sj-Loading.vue │ └── Terms-of-Service.vue ├── config.js ├── filters │ └── index.js ├── main.js ├── router │ └── index.js ├── store │ ├── actions.js │ ├── getters.js │ ├── index.js │ ├── modules │ │ ├── auth.js │ │ ├── billing.js │ │ ├── buckets.js │ │ ├── keypair.js │ │ ├── marketing.js │ │ └── user.js │ └── mutation-types.js ├── theme │ ├── bootstrap.config.js │ ├── bootstrap.config.prod.js │ ├── bootstrap.overrides.scss │ ├── shame.scss │ ├── styles.scss │ ├── theme.scss │ ├── utils.scss │ └── variables.scss ├── utils │ ├── index.js │ └── validation.js ├── vendors │ ├── analytics.js │ ├── storj.es6.js │ └── stripe.js └── views │ ├── Billing │ ├── Add-Card-Form.vue │ ├── Balance-Panel.vue │ ├── Payment-Panel.vue │ ├── Transaction-List.vue │ ├── Usage-Panel.vue │ └── index.vue │ ├── Buckets │ ├── Bucket-Files │ │ ├── Bucket-File-List.vue │ │ └── index.vue │ ├── Bucket-List │ │ ├── Bucket-List-Items.vue │ │ └── index.vue │ ├── Bucket-Settings │ │ ├── Public-Key-List.vue │ │ └── index.vue │ ├── Create-Bucket │ │ └── index.vue │ └── index.vue │ ├── Dashboard │ └── index.vue │ ├── Login │ └── index.vue │ ├── Not-Found │ └── index.vue │ ├── Password-Reset │ ├── index.vue │ └── password-set.vue │ ├── Referrals │ ├── Referral-Email.vue │ ├── Referral-Info.vue │ ├── Referral-Link.vue │ └── index.vue │ ├── Settings │ └── index.vue │ └── Support │ └── index.vue ├── static ├── crossdomain.xml ├── fonts │ ├── AvenirNextLTPro-Bold.woff │ ├── AvenirNextLTPro-Demi.woff │ ├── AvenirNextLTPro-Regular.woff │ ├── glyphicons-halflings-regular.eot │ ├── glyphicons-halflings-regular.svg │ ├── glyphicons-halflings-regular.ttf │ ├── glyphicons-halflings-regular.woff │ └── glyphicons-halflings-regular.woff2 ├── img │ ├── bg.jpg │ ├── favicon │ │ ├── favicon-16x16.png │ │ ├── favicon-32x32.png │ │ ├── favicon-96x96.png │ │ └── favicon.ico │ ├── icon-api.svg │ ├── icon-bandwidth.svg │ ├── icon-bitcoin.svg │ ├── icon-bucket.svg │ ├── icon-capacity.svg │ ├── icon-cli.svg │ ├── icon-cost.svg │ ├── icon-dropdown.svg │ ├── icon-fast.svg │ ├── icon-logo.png │ ├── icon-safe.svg │ ├── icon-storage.svg │ ├── icon-uptime.svg │ ├── icon-users.svg │ ├── icon-web.svg │ ├── logo-amazons3.png │ ├── logo-azure.png │ ├── logo-blue.svg │ ├── logo-white.svg │ ├── metadisk.png │ ├── social-github.svg │ ├── social-reddit.svg │ ├── social-twitter.svg │ ├── storj-loader.svg │ └── storj.png └── robots.txt ├── test ├── e2e │ ├── custom-assertions │ │ └── elementCount.js │ ├── nightwatch.conf.js │ ├── runner.js │ └── specs │ │ └── test.js └── unit │ ├── .eslintrc │ ├── index.js │ ├── karma.conf.js │ └── specs │ └── Hello.spec.js └── vendors ├── analytics.js └── storj.es6.js /.babelrc: -------------------------------------------------------------------------------- 1 | { 2 | "presets": 3 | [ 4 | ["env", { "modules": false }], 5 | "stage-2" 6 | ], 7 | "plugins": ["transform-runtime"], 8 | "comments": false, 9 | "env": { 10 | "test": { 11 | "presets": ["env", "stage-2"], 12 | "plugins": [ "istanbul" ] 13 | }, 14 | "production": { 15 | "presets": ["babili"] 16 | } 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /.dockerignore: -------------------------------------------------------------------------------- 1 | .git 2 | /node_modules/* 3 | -------------------------------------------------------------------------------- /.editorconfig: -------------------------------------------------------------------------------- 1 | root = true 2 | 3 | [*] 4 | charset = utf-8 5 | indent_style = space 6 | indent_size = 2 7 | end_of_line = lf 8 | insert_final_newline = true 9 | trim_trailing_whitespace = true 10 | -------------------------------------------------------------------------------- /.eslintignore: -------------------------------------------------------------------------------- 1 | build/*.js 2 | config/*.js 3 | -------------------------------------------------------------------------------- /.eslintrc.js: -------------------------------------------------------------------------------- 1 | // http://eslint.org/docs/user-guide/configuring 2 | 3 | module.exports = { 4 | root: true, 5 | parser: 'babel-eslint', 6 | parserOptions: { 7 | sourceType: 'module' 8 | }, 9 | env: { 10 | browser: true, 11 | }, 12 | // https://github.com/feross/standard/blob/master/RULES.md#javascript-standard-style 13 | extends: 'standard', 14 | // required to lint *.vue files 15 | plugins: [ 16 | 'html' 17 | ], 18 | // add your custom rules here 19 | 'rules': { 20 | // allow paren-less arrow functions 21 | 'arrow-parens': 0, 22 | // allow async-await 23 | 'generator-star-spacing': 0, 24 | // allow debugger during development 25 | 'no-debugger': process.env.NODE_ENV === 'production' ? 2 : 0, 26 | // add semis :( 27 | 'semi': ['error', 'always'] 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | node_modules/ 3 | npm-debug.log* 4 | yarn-error.log 5 | test/unit/coverage 6 | test/e2e/reports 7 | selenium-debug.log 8 | package.box 9 | .vagrant 10 | .idea/ 11 | logs/ 12 | *.iml 13 | webpack-assets.json 14 | webpack-stats.json 15 | build.log 16 | gems/ 17 | .cache 18 | .node-gyp 19 | .env 20 | .env.* 21 | yarn.lock 22 | -------------------------------------------------------------------------------- /.nvmrc: -------------------------------------------------------------------------------- 1 | 6.9.5 2 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: node_js 2 | 3 | node_js: 4 | - "0.12" 5 | - "4.0" 6 | - "4" 7 | - "stable" 8 | 9 | sudo: false 10 | 11 | before_script: 12 | - export DISPLAY=:99.0 13 | - sh -e /etc/init.d/xvfb start 14 | 15 | script: 16 | - npm run lint 17 | - npm test 18 | - npm run test-node 19 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | Contributing 2 | ============ 3 | 4 | Want to contribute, but not sure where to start? Check out our [issue 5 | board](http://waffle.io/storj/bridge-gui)! 6 | 7 | Pull Requests for Swag 8 | ---------------------- 9 | We love pull requests, so to encourage more of them we are offering 10 | awesome swag. Only SIGNIFICANT pull requests count. Fixing a comma 11 | doesn’t count, but fixing a bug, adding more test coverage, or writing 12 | guides & documentation does. 13 | 14 | - Make 1x pull requests to get into the contributors list and website 15 | - Make 2x pull requests, we will send you a packet of stickers 16 | - Make 5x pull requests, and we will send you a t-shirt and more stickers 17 | - Make 10x pull requests, and you get a job interview with James + other swag 18 | 19 | If we miss a milestones (probably because we are working hard), just let 20 | us know so we can get you your swag. 21 | 22 | Style Guide 23 | ----------- 24 | We adhere to 25 | [Felix's Node.js Style Guide](https://github.com/felixge/node-style-guide). 26 | Please take the time to review the style guide and take care to follow it. 27 | -------------------------------------------------------------------------------- /Jenkinsfile: -------------------------------------------------------------------------------- 1 | node('node') { 2 | try { 3 | 4 | stage 'Checkout' 5 | 6 | checkout scm 7 | 8 | stage 'Build Docker' 9 | 10 | sh "git rev-parse --short HEAD > .git/commit-id" 11 | def commit_id = readFile('.git/commit-id').trim() 12 | sh "./dockerfiles/build.sh storjlabs/bridge-gui-vue ${env.BUILD_ID}" 13 | sh "./dockerfiles/build.sh storjlabs/bridge-gui-vue ${commit_id}" 14 | sh "./dockerfiles/build.sh storjlabs/bridge-gui-vue latest" 15 | 16 | stage 'Test' 17 | /* 18 | sh "docker run storjlabs/bridge-gui-vue-build:${commit_id} 'npm test'" 19 | */ 20 | 21 | stage 'Push' 22 | sh "./dockerfiles/push.sh storjlabs/bridge-gui-vue:${commit_id} storjlabs/bridge-gui-vue:latest" 23 | 24 | stage 'Deploy' 25 | 26 | echo 'Push to Repo' 27 | sh "./dockerfiles/deploy.staging.sh bridge-gui-vue storjlabs/bridge-gui-vue:${commit_id}" 28 | 29 | stage 'Cleanup' 30 | 31 | echo 'prune and cleanup' 32 | sh """#!/bin/bash -e 33 | source '/var/lib/jenkins/.nvm/nvm.sh' 34 | rm node_modules -rf 35 | """ 36 | } 37 | 38 | catch (err) { 39 | currentBuild.result = "FAILURE" 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | _**Notice**: Development on this repo is deprecated as we continue our v3 rearchitecture. Please see https://github.com/storj/storj for ongoing v3 development._ 2 | 3 | # bridge-gui-vue 4 | 5 | > A web-based GUI for Storj Bridge 6 | 7 | ## Local Development Setup 8 | 9 | ### Prerequisites 10 | 11 | 1. Nodemon 12 | - Installation: `npm install -g nodemon` 13 | 14 | 2. Mongodb 15 | 16 | - Installation: `brew update && brew install mongodb` 17 | 18 | - If you don't have Mac OSX, follow the [install instructions](https://docs.mongodb.com/manual/tutorial/install-mongodb-on-os-x/) 19 | 20 | - If you don't have Homebrew, [install it](https://brew.sh/) 21 | 22 | - As an easy way to manage Mongo and other databases, I recommend [Launch Rocket](https://github.com/jimbojsb/launchrocket). Install with `brew cask install launchrocket`. This will allow you to easily turn Mongo on and off and even have it start automatically. 23 | 24 | - Start Mongo with `mongod` in a new terminal window. If you don't use Launch Rocket, then you'll need to follow the [Mongo instructions](https://docs.mongodb.com/manual/tutorial/install-mongodb-on-os-x/#run-mongodb) to start it 25 | 26 | 3. Redis 27 | 28 | - Installation: `brew update && brew install redis` 29 | 30 | - Just get Launch Rocket by now to start and manage all your databases 31 | 32 | 4. Node >= v.6.9.4 33 | 34 | ### Create `storj-dev` folder 35 | > Optional: You don't need this folder, but it may help in organizing if you've got a lot going on 36 | 37 | ```sh 38 | $ mkdir storj-dev 39 | $ cd storj-dev 40 | ``` 41 | 42 | ### Git clone all the repos 43 | 44 | ```sh 45 | $ git clone https://github.com/Storj/bridge.git 46 | $ git clone https://github.com/Storj/billing.git 47 | $ git clone https://github.com/Storj/bridge-gui-vue.git 48 | ``` 49 | 50 | Open up two more terminal windows and navigate to the `storj-dev` folder 51 | 52 | ### Setup bridge 53 | 54 | In the first one, navigate to `storj-dev/bridge` 55 | 56 | ```sh 57 | $ npm install && npm link 58 | $ NODE_ENV=develop storj-bridge 59 | ``` 60 | 61 | If it's running correctly, you should see output like this: 62 | 63 | ```sh 64 | {"level":"info","message":"starting the bridge engine","timestamp":"2017-04-28T20:47:51.665Z"} 65 | {"level":"info","message":"opening database connection to mongodb://127.0.0.1:27017/__storj-bridge-develop","timestamp":"2017-04-28T20:47:51.666Z"} 66 | {"level":"info","message":"configuring service endpoints","timestamp":"2017-04-28T20:47:51.688Z"} 67 | {"level":"info","message":"setting up http(s) server instance","timestamp":"2017-04-28T20:47:51.701Z"} 68 | {"level":"info","message":"connected to database","timestamp":"2017-04-28T20:47:51.718Z"} 69 | ``` 70 | 71 | ### Setup billing 72 | 73 | In another terminal window, navigate to `storj-dev/billing` 74 | 75 | Create a `.env file` for storing billing variables 76 | 77 | ```sh 78 | $ touch .env 79 | ``` 80 | 81 | Paste your `STRIPE_KEY=stripe_test_key` into the `.env` file. 82 | 83 | ```sh 84 | $ npm install 85 | $ npm run start:dev 86 | ``` 87 | 88 | If it's running correctly, you should see output like this: 89 | 90 | ```sh 91 | > storj-billing@0.2.0 start-dev /Users/barbara/Documents/Code/storj-dev/billing 92 | > NODE_ENV=develop nodemon ./bin/storj-billing.js 93 | 94 | [nodemon] 1.11.0 95 | [nodemon] to restart at any time, enter `rs` 96 | [nodemon] watching: *.* 97 | [nodemon] starting `node ./bin/storj-billing.js` 98 | **** server listening on 3000 99 | {"level":"info","message":"starting the billing engine","timestamp":"2017-04-28T20:51:26.215Z"} 100 | {"level":"info","message":"opening database connection","timestamp":"2017-04-28T20:51:26.216Z"} 101 | {"level":"info","message":"configuring service endpoints","timestamp":"2017-04-28T20:51:26.238Z"} 102 | {"level":"info","message":"setting up http(s) server instance","timestamp":"2017-04-28T20:51:26.308Z"} 103 | {"level":"info","message":"connected to database","timestamp":"2017-04-28T20:51:26.325Z"} 104 | ``` 105 | 106 | ### bridge-gui-vue 107 | 108 | In the last terminal window, navigate to `storj-dev/bridge-gui-vue` 109 | 110 | Create a `.env` file to hold app secrets 111 | 112 | ```sh 113 | $ touch .env 114 | ``` 115 | 116 | Inside, you'll need to add this: 117 | 118 | ``` 119 | STRIPE_PUBLISHABLE_KEY=test_key 120 | ``` 121 | 122 | Then, you can start up everything 123 | 124 | ```sh 125 | $ npm install 126 | $ npm run dev 127 | ``` 128 | 129 | The initial load takes around ~17 secs, but every other load after that is ~0.5-2 seconds 130 | 131 | If running correctly, you'll see output like this: 132 | 133 | ```bash 134 | > bridge-gui-vue@1.0.0 dev /Users/barbara/Documents/Code/storj-vagrant/bridge-gui-vue 135 | > node build/dev-server.js 136 | 137 | 138 | 139 | DONE Compiled successfully in 16180ms 4:27:05 PM 140 | 141 | > Listening at http://localhost:3001 142 | ``` 143 | 144 | Open up `localhost:3001`. Now, upon making changes and saving the file, the app will hot reload and display those changes. 145 | -------------------------------------------------------------------------------- /build/build.js: -------------------------------------------------------------------------------- 1 | require('./check-versions')() 2 | 3 | process.env.NODE_ENV = 'production' 4 | 5 | var ora = require('ora') 6 | var rm = require('rimraf') 7 | var path = require('path') 8 | var chalk = require('chalk') 9 | var webpack = require('webpack') 10 | var config = require('../config') 11 | var webpackConfig = require('./webpack.prod.conf') 12 | 13 | var spinner = ora('building for production...') 14 | spinner.start() 15 | 16 | rm(path.join(config.build.assetsRoot, config.build.assetsSubDirectory), err => { 17 | if (err) throw err 18 | webpack(webpackConfig, function (err, stats) { 19 | spinner.stop() 20 | if (err) throw err 21 | process.stdout.write(stats.toString({ 22 | colors: true, 23 | modules: false, 24 | children: false, 25 | chunks: false, 26 | chunkModules: false 27 | }) + '\n\n') 28 | 29 | console.log(chalk.cyan(' Build complete.\n')) 30 | console.log(chalk.yellow( 31 | ' Tip: built files are meant to be served over an HTTP server.\n' + 32 | ' Opening index.html over file:// won\'t work.\n' 33 | )) 34 | }) 35 | }) 36 | -------------------------------------------------------------------------------- /build/check-versions.js: -------------------------------------------------------------------------------- 1 | var chalk = require('chalk') 2 | var semver = require('semver') 3 | var packageConfig = require('../package.json') 4 | 5 | function exec (cmd) { 6 | return require('child_process').execSync(cmd).toString().trim() 7 | } 8 | 9 | var versionRequirements = [ 10 | { 11 | name: 'node', 12 | currentVersion: semver.clean(process.version), 13 | versionRequirement: packageConfig.engines.node 14 | }, 15 | { 16 | name: 'npm', 17 | currentVersion: exec('npm --version'), 18 | versionRequirement: packageConfig.engines.npm 19 | } 20 | ] 21 | 22 | module.exports = function () { 23 | var warnings = [] 24 | for (var i = 0; i < versionRequirements.length; i++) { 25 | var mod = versionRequirements[i] 26 | if (!semver.satisfies(mod.currentVersion, mod.versionRequirement)) { 27 | warnings.push(mod.name + ': ' + 28 | chalk.red(mod.currentVersion) + ' should be ' + 29 | chalk.green(mod.versionRequirement) 30 | ) 31 | } 32 | } 33 | 34 | if (warnings.length) { 35 | console.log('') 36 | console.log(chalk.yellow('To use this template, you must update following to modules:')) 37 | console.log() 38 | for (var i = 0; i < warnings.length; i++) { 39 | var warning = warnings[i] 40 | console.log(' ' + warning) 41 | } 42 | console.log() 43 | process.exit(1) 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /build/dev-client.js: -------------------------------------------------------------------------------- 1 | /* eslint-disable */ 2 | require('eventsource-polyfill') 3 | var hotClient = require('webpack-hot-middleware/client?noInfo=true&reload=true') 4 | 5 | hotClient.subscribe(function (event) { 6 | if (event.action === 'reload') { 7 | window.location.reload() 8 | } 9 | }) 10 | -------------------------------------------------------------------------------- /build/dev-server.js: -------------------------------------------------------------------------------- 1 | require('./check-versions')() 2 | 3 | var config = require('../config') 4 | if (!process.env.NODE_ENV) { 5 | process.env.NODE_ENV = JSON.parse(config.dev.env.NODE_ENV) 6 | } 7 | 8 | var opn = require('opn') 9 | var path = require('path') 10 | var express = require('express') 11 | var webpack = require('webpack') 12 | var proxyMiddleware = require('http-proxy-middleware') 13 | var webpackConfig = process.env.NODE_ENV === 'testing' 14 | ? require('./webpack.prod.conf') 15 | : require('./webpack.dev.conf') 16 | var Dashboard = require('webpack-dashboard') 17 | var DashboardPlugin = require('webpack-dashboard/plugin') 18 | 19 | // default port where dev server listens for incoming traffic 20 | var port = process.env.PORT || config.dev.port 21 | // automatically open browser, if not set will be false 22 | var autoOpenBrowser = !!config.dev.autoOpenBrowser 23 | // Define HTTP proxies to your custom API backend 24 | // https://github.com/chimurai/http-proxy-middleware 25 | var proxyTable = config.dev.proxyTable 26 | 27 | var app = express() 28 | var compiler = webpack(webpackConfig) 29 | 30 | var devMiddleware = require('webpack-dev-middleware')(compiler, { 31 | publicPath: webpackConfig.output.publicPath, 32 | quiet: true 33 | }) 34 | 35 | var hotMiddleware = require('webpack-hot-middleware')(compiler, { 36 | log: () => {} 37 | }) 38 | 39 | // force page reload when html-webpack-plugin template changes 40 | compiler.plugin('compilation', function (compilation) { 41 | compilation.plugin('html-webpack-plugin-after-emit', function (data, cb) { 42 | hotMiddleware.publish({ action: 'reload' }) 43 | cb() 44 | }) 45 | }) 46 | 47 | // Setup webpack dashboard 48 | var dashboard = new Dashboard() 49 | compiler.apply(new DashboardPlugin(dashboard.setData)) 50 | 51 | // proxy api requests 52 | Object.keys(proxyTable).forEach(function (context) { 53 | var options = proxyTable[context] 54 | if (typeof options === 'string') { 55 | options = { target: options } 56 | } 57 | app.use(proxyMiddleware(options.filter || context, options)) 58 | }) 59 | 60 | // handle fallback for HTML5 history API 61 | app.use(require('connect-history-api-fallback')()) 62 | 63 | // serve webpack bundle output 64 | app.use(devMiddleware) 65 | 66 | // enable hot-reload and state-preserving 67 | // compilation error display 68 | app.use(hotMiddleware) 69 | 70 | // serve pure static assets 71 | var staticPath = path.posix.join(config.dev.assetsPublicPath, config.dev.assetsSubDirectory) 72 | app.use(staticPath, express.static('./static')) 73 | 74 | var uri = 'http://localhost:' + port 75 | 76 | devMiddleware.waitUntilValid(function () { 77 | console.log('> Listening at ' + uri + '\n') 78 | }) 79 | 80 | module.exports = app.listen(port, function (err) { 81 | if (err) { 82 | console.log(err) 83 | return 84 | } 85 | 86 | // when env is testing, don't need open it 87 | if (autoOpenBrowser && process.env.NODE_ENV !== 'testing') { 88 | opn(uri) 89 | } 90 | }) 91 | -------------------------------------------------------------------------------- /build/utils.js: -------------------------------------------------------------------------------- 1 | var path = require('path') 2 | var config = require('../config') 3 | var ExtractTextPlugin = require('extract-text-webpack-plugin') 4 | 5 | exports.assetsPath = function (_path) { 6 | var assetsSubDirectory = process.env.NODE_ENV === 'production' 7 | ? config.build.assetsSubDirectory 8 | : config.dev.assetsSubDirectory 9 | return path.posix.join(assetsSubDirectory, _path) 10 | } 11 | 12 | exports.cssLoaders = function (options) { 13 | options = options || {} 14 | 15 | var cssLoader = { 16 | loader: 'css-loader', 17 | options: { 18 | minimize: process.env.NODE_ENV === 'production', 19 | sourceMap: options.sourceMap 20 | } 21 | } 22 | 23 | // generate loader string to be used with extract text plugin 24 | function generateLoaders (loader, loaderOptions) { 25 | var loaders = [cssLoader] 26 | if (loader) { 27 | loaders.push({ 28 | loader: loader + '-loader', 29 | options: Object.assign({}, loaderOptions, { 30 | sourceMap: options.sourceMap 31 | }) 32 | }) 33 | } 34 | 35 | // Extract CSS when that option is specified 36 | // (which is the case during production build) 37 | if (options.extract) { 38 | return ExtractTextPlugin.extract({ 39 | use: loaders, 40 | fallback: 'vue-style-loader' 41 | }) 42 | } else { 43 | return ['vue-style-loader'].concat(loaders) 44 | } 45 | } 46 | 47 | // http://vuejs.github.io/vue-loader/en/configurations/extract-css.html 48 | return { 49 | css: generateLoaders(), 50 | postcss: generateLoaders(), 51 | less: generateLoaders('less'), 52 | sass: generateLoaders('sass', { indentedSyntax: true }), 53 | scss: generateLoaders('sass'), 54 | stylus: generateLoaders('stylus'), 55 | styl: generateLoaders('stylus') 56 | } 57 | } 58 | 59 | // Generate loaders for standalone style files (outside of .vue) 60 | exports.styleLoaders = function (options) { 61 | var output = [] 62 | var loaders = exports.cssLoaders(options) 63 | for (var extension in loaders) { 64 | var loader = loaders[extension] 65 | output.push({ 66 | test: new RegExp('\\.' + extension + '$'), 67 | use: loader 68 | }) 69 | } 70 | return output 71 | } 72 | -------------------------------------------------------------------------------- /build/vue-loader.conf.js: -------------------------------------------------------------------------------- 1 | var utils = require('./utils') 2 | var config = require('../config') 3 | var isProduction = process.env.NODE_ENV === 'production' 4 | 5 | module.exports = { 6 | loaders: utils.cssLoaders({ 7 | sourceMap: isProduction 8 | ? config.build.productionSourceMap 9 | : config.dev.cssSourceMap, 10 | extract: isProduction 11 | }) 12 | } 13 | -------------------------------------------------------------------------------- /build/webpack.base.conf.js: -------------------------------------------------------------------------------- 1 | var path = require('path') 2 | var utils = require('./utils') 3 | var config = require('../config') 4 | var vueLoaderConfig = require('./vue-loader.conf') 5 | 6 | function resolve (dir) { 7 | return path.join(__dirname, '..', dir) 8 | } 9 | 10 | module.exports = { 11 | entry: { 12 | app: './src/main.js', 13 | vendor: [ 14 | 'lodash', 15 | 'moment', 16 | resolve('vendors/storj.es6.js'), 17 | resolve('vendors/analytics.js') 18 | ] 19 | }, 20 | output: { 21 | path: config.build.assetsRoot, 22 | filename: '[name].js', 23 | publicPath: process.env.NODE_ENV === 'production' 24 | ? config.build.assetsPublicPath 25 | : config.dev.assetsPublicPath 26 | }, 27 | resolve: { 28 | extensions: ['.js', '.vue', '.json'], 29 | alias: { 30 | 'vue$': 'vue/dist/vue.esm.js', 31 | '@': resolve('src') 32 | } 33 | }, 34 | module: { 35 | rules: [ 36 | { 37 | test: /\.(js|vue)$/, 38 | loader: 'eslint-loader', 39 | enforce: "pre", 40 | include: [resolve('src'), resolve('test')], 41 | options: { 42 | formatter: require('eslint-friendly-formatter') 43 | } 44 | }, 45 | { 46 | test: /\.vue$/, 47 | loader: 'vue-loader', 48 | options: vueLoaderConfig 49 | }, 50 | { 51 | test: /\.js$/, 52 | loader: 'babel-loader', 53 | include: [resolve('src'), resolve('test')] 54 | }, 55 | { 56 | test: /\.(png|jpe?g|gif|svg)(\?.*)?$/, 57 | loader: 'url-loader', 58 | query: { 59 | limit: 10000, 60 | name: utils.assetsPath('img/[name].[hash:7].[ext]') 61 | } 62 | }, 63 | { 64 | test: /\.(woff2?|eot|ttf|otf)(\?.*)?$/, 65 | loader: 'url-loader', 66 | query: { 67 | limit: 10000, 68 | name: utils.assetsPath('fonts/[name].[hash:7].[ext]') 69 | } 70 | } 71 | ] 72 | } 73 | } 74 | -------------------------------------------------------------------------------- /build/webpack.dev.conf.js: -------------------------------------------------------------------------------- 1 | var utils = require('./utils') 2 | var webpack = require('webpack') 3 | var config = require('../config') 4 | var merge = require('webpack-merge') 5 | var baseWebpackConfig = require('./webpack.base.conf') 6 | var HtmlWebpackPlugin = require('html-webpack-plugin') 7 | var FriendlyErrorsPlugin = require('friendly-errors-webpack-plugin') 8 | var DotenvPlugin = require('dotenv-webpack') 9 | var DashboardPlugin = require('webpack-dashboard/plugin'); 10 | 11 | // add hot-reload related code to entry chunks 12 | Object.keys(baseWebpackConfig.entry).forEach(function (name) { 13 | baseWebpackConfig.entry[name] = ['./build/dev-client'].concat(baseWebpackConfig.entry[name]) 14 | }) 15 | 16 | module.exports = merge(baseWebpackConfig, { 17 | 18 | module: { 19 | rules: utils.styleLoaders({ sourceMap: config.dev.cssSourceMap }) 20 | }, 21 | // cheap-module-eval-source-map is faster for development 22 | devtool: '#cheap-module-eval-source-map', 23 | plugins: [ 24 | new webpack.DefinePlugin({ 25 | 'process.env': require('../config/dev.env') 26 | }), 27 | // https://github.com/glenjamin/webpack-hot-middleware#installation--usage 28 | new webpack.HotModuleReplacementPlugin(), 29 | new webpack.NoEmitOnErrorsPlugin(), 30 | // https://github.com/ampedandwired/html-webpack-plugin 31 | new HtmlWebpackPlugin({ 32 | filename: 'index.html', 33 | template: 'index.html', 34 | inject: true 35 | }), 36 | new FriendlyErrorsPlugin(), 37 | new DotenvPlugin({ 38 | path: './.env', 39 | systemvars: true 40 | })] 41 | }) 42 | -------------------------------------------------------------------------------- /build/webpack.prod.conf.js: -------------------------------------------------------------------------------- 1 | var path = require('path') 2 | var utils = require('./utils') 3 | var webpack = require('webpack') 4 | var config = require('../config') 5 | var merge = require('webpack-merge') 6 | var baseWebpackConfig = require('./webpack.base.conf') 7 | var CopyWebpackPlugin = require('copy-webpack-plugin') 8 | var HtmlWebpackPlugin = require('html-webpack-plugin') 9 | var ExtractTextPlugin = require('extract-text-webpack-plugin') 10 | var OptimizeCSSPlugin = require('optimize-css-assets-webpack-plugin') 11 | var BabiliPlugin = require('babili-webpack-plugin') 12 | var Dotenv = require('dotenv-webpack') 13 | 14 | var env = process.env.NODE_ENV === 'testing' 15 | ? require('../config/test.env') 16 | : config.build.env 17 | 18 | var webpackConfig = merge(baseWebpackConfig, { 19 | module: { 20 | rules: utils.styleLoaders({ 21 | sourceMap: config.build.productionSourceMap, 22 | extract: true 23 | }) 24 | }, 25 | devtool: config.build.productionSourceMap ? '#source-map' : false, 26 | output: { 27 | path: config.build.assetsRoot, 28 | filename: utils.assetsPath('js/[name].[chunkhash].js'), 29 | chunkFilename: utils.assetsPath('js/[id].[chunkhash].js') 30 | }, 31 | plugins: [ 32 | new Dotenv({ 33 | path: './.env', 34 | systemvars: true 35 | }), 36 | // can't uglify es2015 stuff yet. Using babili 37 | // new webpack.optimize.UglifyJsPlugin({ 38 | // compress: { 39 | // warnings: false 40 | // }, 41 | // sourceMap: true 42 | // }), 43 | // new BabiliPlugin({}), 44 | // extract css into its own file 45 | new ExtractTextPlugin({ 46 | filename: utils.assetsPath('css/[name].[contenthash].css') 47 | }), 48 | // Compress extracted CSS. We are using this plugin so that possible 49 | // duplicated CSS from different components can be deduped. 50 | new OptimizeCSSPlugin(), 51 | // generate dist index.html with correct asset hash for caching. 52 | // you can customize output by editing /index.html 53 | // see https://github.com/ampedandwired/html-webpack-plugin 54 | new HtmlWebpackPlugin({ 55 | filename: process.env.NODE_ENV === 'testing' 56 | ? 'index.html' 57 | : config.build.index, 58 | template: 'index.html', 59 | inject: true, 60 | minify: { 61 | removeComments: true, 62 | collapseWhitespace: true, 63 | removeAttributeQuotes: true 64 | // more options: 65 | // https://github.com/kangax/html-minifier#options-quick-reference 66 | }, 67 | // necessary to consistently work with multiple chunks via CommonsChunkPlugin 68 | chunksSortMode: 'dependency' 69 | }), 70 | // split vendor js into its own file 71 | new webpack.optimize.CommonsChunkPlugin({ 72 | name: 'vendor', 73 | minChunks: function (module, count) { 74 | // any required modules inside node_modules are extracted to vendor 75 | return ( 76 | module.resource && 77 | /\.js$/.test(module.resource) && 78 | module.resource.indexOf( 79 | path.join(__dirname, '../node_modules') 80 | ) === 0 81 | ) 82 | } 83 | }), 84 | // extract webpack runtime and module manifest to its own file in order to 85 | // prevent vendor hash from being updated whenever app bundle is updated 86 | new webpack.optimize.CommonsChunkPlugin({ 87 | name: 'manifest', 88 | chunks: ['vendor'] 89 | }), 90 | // copy custom static assets 91 | new CopyWebpackPlugin([ 92 | { 93 | from: path.resolve(__dirname, '../static'), 94 | to: config.build.assetsSubDirectory, 95 | ignore: ['.*'] 96 | } 97 | ]) 98 | ] 99 | }) 100 | 101 | if (config.build.productionGzip) { 102 | var CompressionWebpackPlugin = require('compression-webpack-plugin') 103 | 104 | webpackConfig.plugins.push( 105 | new CompressionWebpackPlugin({ 106 | asset: '[path].gz[query]', 107 | algorithm: 'gzip', 108 | test: new RegExp( 109 | '\\.(' + 110 | config.build.productionGzipExtensions.join('|') + 111 | ')$' 112 | ), 113 | threshold: 10240, 114 | minRatio: 0.8 115 | }) 116 | ) 117 | } 118 | 119 | if (config.build.bundleAnalyzerReport) { 120 | var BundleAnalyzerPlugin = require('webpack-bundle-analyzer').BundleAnalyzerPlugin 121 | webpackConfig.plugins.push(new BundleAnalyzerPlugin()) 122 | } 123 | 124 | module.exports = webpackConfig 125 | -------------------------------------------------------------------------------- /build/webpack.test.conf.js: -------------------------------------------------------------------------------- 1 | // This is the webpack config used for unit tests. 2 | 3 | var utils = require('./utils') 4 | var webpack = require('webpack') 5 | var merge = require('webpack-merge') 6 | var baseConfig = require('./webpack.base.conf') 7 | 8 | var webpackConfig = merge(baseConfig, { 9 | // use inline sourcemap for karma-sourcemap-loader 10 | module: { 11 | rules: utils.styleLoaders() 12 | }, 13 | devtool: '#inline-source-map', 14 | plugins: [ 15 | new webpack.DefinePlugin({ 16 | 'process.env': require('../config/test.env') 17 | }) 18 | ] 19 | }) 20 | 21 | // no need for app entry during tests 22 | delete webpackConfig.entry 23 | 24 | module.exports = webpackConfig 25 | -------------------------------------------------------------------------------- /config/dev.env.js: -------------------------------------------------------------------------------- 1 | var merge = require('webpack-merge') 2 | var prodEnv = require('./prod.env') 3 | 4 | module.exports = merge(prodEnv, { 5 | NODE_ENV: '"development"' 6 | }) 7 | -------------------------------------------------------------------------------- /config/index.js: -------------------------------------------------------------------------------- 1 | // see http://vuejs-templates.github.io/webpack for documentation. 2 | var path = require('path') 3 | 4 | module.exports = { 5 | build: { 6 | env: require('./prod.env'), 7 | index: path.resolve(__dirname, '../dist/index.html'), 8 | assetsRoot: path.resolve(__dirname, '../dist'), 9 | assetsSubDirectory: 'static', 10 | assetsPublicPath: '/', 11 | productionSourceMap: true, 12 | // Gzip off by default as many popular static hosts such as 13 | // Surge or Netlify already gzip all static assets for you. 14 | // Before setting to `true`, make sure to: 15 | // npm install --save-dev compression-webpack-plugin 16 | productionGzip: false, 17 | productionGzipExtensions: ['js', 'css'], 18 | // Run the build command with an extra argument to 19 | // View the bundle analyzer report after build finishes: 20 | // `npm run build --report` 21 | // Set to `true` or `false` to always turn it on or off 22 | bundleAnalyzerReport: process.env.npm_config_report 23 | }, 24 | dev: { 25 | env: require('./dev.env'), 26 | port: 3001, 27 | autoOpenBrowser: false, 28 | assetsSubDirectory: 'static', 29 | assetsPublicPath: '/', 30 | proxyTable: {}, 31 | // CSS Sourcemaps off by default because relative paths are "buggy" 32 | // with this option, according to the CSS-Loader README 33 | // (https://github.com/webpack/css-loader#sourcemaps) 34 | // In our experience, they generally work as expected, 35 | // just be aware of this issue when enabling this option. 36 | cssSourceMap: false 37 | }, 38 | app: { 39 | NAME: 'storj-bridge-gui', 40 | BRIDGE_URL: process.env.NODE_ENV === 'development' 41 | ? 'http://localhost:6382' : process.env.BRIDGE_URL, 42 | BILLING_URL: process.env.NODE_ENV === 'development' 43 | ? 'http://localhost:3000' : process.env.BILLING_URL 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /config/prod.env.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | NODE_ENV: process.env.NODE_ENV, 3 | STRIPE_PUBLISHABLE_KEY: process.env.STRIPE_PUBLISHABLE_KEY, 4 | BILLING_URL: process.env.BILLING_URL, 5 | BRIDGE_URL: process.env.BRIDGE_URL 6 | } 7 | -------------------------------------------------------------------------------- /config/test.env.js: -------------------------------------------------------------------------------- 1 | var merge = require('webpack-merge') 2 | var devEnv = require('./dev.env') 3 | 4 | module.exports = merge(devEnv, { 5 | NODE_ENV: '"testing"' 6 | }) 7 | -------------------------------------------------------------------------------- /dist/.gitignore: -------------------------------------------------------------------------------- 1 | * 2 | !.gitignore 3 | !*/ 4 | -------------------------------------------------------------------------------- /dockerfiles/build.dockerfile: -------------------------------------------------------------------------------- 1 | FROM node:6.10 2 | 3 | RUN mkdir /opt/bridge-gui-vue 4 | RUN mkdir /opt/bridge-gui-vue/dist 5 | 6 | COPY ./package.json /opt/bridge-gui-vue/package.json 7 | 8 | WORKDIR /opt/bridge-gui-vue/ 9 | 10 | RUN npm install 11 | 12 | COPY . /opt/bridge-gui-vue/ 13 | 14 | ARG NODE_ENV=NODE_ENV_ENV 15 | ARG BILLING_URL=BILLING_URL_ENV 16 | ARG BRIDGE_URL=BRIDGE_URL_ENV 17 | ARG STRIPE_PUBLISHABLE_KEY=STRIPE_PUBLISHABLE_KEY_ENV 18 | 19 | ENV NODE_ENV $NODE_ENV 20 | ENV BILLING_URL $BILLING_URL 21 | ENV BRIDGE_URL $BRIDGE_URL 22 | ENV STRIPE_PUBLISHABLE_KEY $STRIPE_PUBLISHABLE_KEY 23 | 24 | #CMD ["npm", "run", "build"] 25 | CMD exec /bin/bash -c "trap : TERM INT; sleep infinity & wait" 26 | -------------------------------------------------------------------------------- /dockerfiles/build.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | #npm run build 4 | 5 | NAME=$1 6 | TAG=$2 7 | 8 | echo "Building with NAME: ${NAME} and TAG: ${TAG}" 9 | 10 | # We need to pass in the version portion of the tag so we can tag both the serve and build containers 11 | BUILD_OUTPUT=$(docker build -t ${NAME}-build:${TAG} -f ./dockerfiles/build.dockerfile .) 12 | result=$? 13 | 14 | if [[ $result != 0 ]]; then 15 | echo "Error building docker image" 16 | exit 1 17 | fi 18 | 19 | #BUILD_ID=$(docker images -q ${NAME}-build:${TAG}) 20 | 21 | echo "Build ID is $BUILD_ID" 22 | 23 | # CMD exec /bin/bash -c "trap : TERM INT; sleep infinity & wait" 24 | 25 | echo "Starting build container" 26 | CONTAINER_ID=$(docker run -d ${NAME}-build:${TAG}) 27 | 28 | echo "Running build in container with id $CONTAINER_ID" 29 | docker exec -t $CONTAINER_ID npm run build 30 | echo "Build done." 31 | 32 | echo "Copying statically built files to local dist directory" 33 | docker cp $CONTAINER_ID:/opt/bridge-gui-vue/dist/ . 34 | 35 | echo "Creating server container from static files" 36 | docker build -t ${NAME}:${TAG} -f ./dockerfiles/serve.dockerfile . 37 | echo "Server container creation done." 38 | 39 | if [[ $result != 0 ]]; then 40 | echo "Error building docker image" 41 | exit 1 42 | fi 43 | 44 | echo "Success..." 45 | exit 0 46 | -------------------------------------------------------------------------------- /dockerfiles/deploy.staging.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | PROJECT_NAME=$1 4 | CONTAINER=$2 5 | 6 | kubectl config set-cluster storj-nonprod 7 | kubectl --namespace storj-staging patch deployment $PROJECT_NAME -p"{\"spec\":{\"template\":{\"spec\":{\"containers\":[{\"name\":\"$PROJECT_NAME\",\"image\":\"$CONTAINER\"}]}}}}" 8 | -------------------------------------------------------------------------------- /dockerfiles/files/certs.dev/cert.pem: -------------------------------------------------------------------------------- 1 | -----BEGIN CERTIFICATE----- 2 | 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 35 | sdWvujYnEfb1PA== 36 | -----END CERTIFICATE----- 37 | -------------------------------------------------------------------------------- /dockerfiles/files/certs.dev/dhparams.pem: -------------------------------------------------------------------------------- 1 | -----BEGIN DH PARAMETERS----- 2 | MIIBCAKCAQEAx4e8qgm321n6WZa5kf5wEbsDoQsvtDMFqvO2IONFcO9ZD8+MrTkv 3 | 7r/VWIqIsGqeJDDBO5vTsth9fhLoo+/Fpe/f7436AF3+0l1hRzYYDCQIiIpNgzYo 4 | 18Wxbq2TXsTNxH53uuGIonDNAassBpCcDikLjojE8Pjn/tMAXK+KTQZHkbu1JLOn 5 | rpJmhv7uWeKpb76xkPgZ4DKou00u4DQgEagGVY6NUGGLbHXRVZ1joaqSUBYnlJhX 6 | rcfHBcA6SICmJ7RfRI0lr8HotZwgdZOzznFEihVSTXxe366kvVsvgKqMNEPvpxlW 7 | YECOb7kG5OqC7jrAPttB/Tw4O55s4TWf6wIBAg== 8 | -----END DH PARAMETERS----- 9 | -------------------------------------------------------------------------------- /dockerfiles/files/certs.dev/key.pem: -------------------------------------------------------------------------------- 1 | -----BEGIN RSA PRIVATE KEY----- 2 | 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 51 | -----END RSA PRIVATE KEY----- 52 | -------------------------------------------------------------------------------- /dockerfiles/files/configs/nginx-default: -------------------------------------------------------------------------------- 1 | server { 2 | root /var/www; 3 | index index.html index.htm; 4 | 5 | # Make site accessible from http://localhost/ 6 | server_name localhost; 7 | 8 | # Mitigate clickjacking 9 | add_header X-Frame-Options "DENY"; 10 | 11 | # Add 1 day expires header for static assets 12 | location ~* \.(js|css|png|jpg|jpeg|gif|ico)$ { 13 | expires 1d; 14 | } 15 | 16 | location / { 17 | # First attempt to serve request as file, then 18 | # as directory, then fall back to redirecting to index.html 19 | try_files $uri $uri/ /index.html; 20 | } 21 | 22 | include /etc/nginx/basic.conf; 23 | } 24 | 25 | -------------------------------------------------------------------------------- /dockerfiles/files/configs/nginx-default-ssl: -------------------------------------------------------------------------------- 1 | server { 2 | listen 443; 3 | 4 | root /var/www; 5 | index index.html index.htm; 6 | 7 | location / { 8 | try_files $uri $uri/ /index.html; 9 | } 10 | 11 | ssl on; 12 | ssl_certificate /etc/nginx/ssl/server.crt; 13 | ssl_certificate_key /etc/nginx/ssl/server.key; 14 | } 15 | -------------------------------------------------------------------------------- /dockerfiles/files/scripts/helpers/logger/index.js: -------------------------------------------------------------------------------- 1 | import {ensureLogsDir, ensureLogsDirSync} from './utils'; 2 | import seleniumLogger from './selenium'; 3 | 4 | export { 5 | ensureLogsDir, 6 | ensureLogsDirSync, 7 | seleniumLogger 8 | }; 9 | -------------------------------------------------------------------------------- /dockerfiles/files/scripts/helpers/logger/selenium.js: -------------------------------------------------------------------------------- 1 | import fs from 'fs'; 2 | import path from 'path'; 3 | import {ensureLogsDirSync} from './utils'; 4 | 5 | const dirPath = ensureLogsDirSync(); 6 | const fd = fs.openSync(path.resolve(dirPath, 'selenium.log'), 'a'); 7 | 8 | export default {fd}; 9 | -------------------------------------------------------------------------------- /dockerfiles/files/scripts/helpers/logger/utils.js: -------------------------------------------------------------------------------- 1 | import fs from 'fs'; 2 | import path from 'path'; 3 | const logDir = process.env.LOG_DIR || path.resolve(__dirname, '../../../logs'); 4 | 5 | /** 6 | * Asynchronously Ensures the log directory is present 7 | * @param {Function} done - callback which is called once the directory is stat'ed or created 8 | * @param {String} [dirPath=LOG_DIR or /logs] - path of the directory in which logs should be written to 9 | */ 10 | export const ensureLogsDir = (done, dirPath = logDir) => { 11 | /** 12 | * Done callback 13 | * @callback done 14 | * @param {String} dirPath=LOG_DIR or /logs - path of the directory in which logs should be written to 15 | */ 16 | fs.stat(dirPath, (err, stats) => { 17 | if (!!stats && stats.isDirectory()) { 18 | // directory exists 19 | return done(dirPath); 20 | } 21 | 22 | const mkdirErr = fs.mkdirSync(dirPath); 23 | if (mkdirErr) throw mkdirErr; 24 | done(dirPath); 25 | }); 26 | }; 27 | 28 | /** 29 | * Ensures the log directory is present 30 | * @param {String} [dirPath=LOG_DIR or /logs] - path of the directory in which logs should be written to 31 | * @return {String} dirPath - the path of the logDir 32 | */ 33 | export const ensureLogsDirSync = (dirPath = logDir) => { 34 | const mkdir = () => { 35 | const mkdirErr = fs.mkdirSync(dirPath); 36 | if (mkdirErr) throw mkdirErr; 37 | return dirPath; 38 | }; 39 | try { 40 | const stats = fs.statSync(dirPath); 41 | if (!!stats && stats.isDirectory()) { 42 | // directory exists 43 | return dirPath; 44 | } 45 | 46 | // file exists with same name as directory 47 | return mkdir(); 48 | } catch (err) { 49 | // directory doesn't exist 50 | return mkdir(); 51 | } 52 | }; 53 | -------------------------------------------------------------------------------- /dockerfiles/files/scripts/helpers/processes.js: -------------------------------------------------------------------------------- 1 | const noop = () => {}; 2 | 3 | /** 4 | * Ensures `processesToKill` and their child processes are killed 5 | * when `exitingProcess` exits, receives `SIGINT`, or has an 6 | * uncaught exception 7 | * @param {ChildProcess} exitingProcess - process to watch 8 | * @param {Array.} processesToKill - processes to kill 9 | */ 10 | export const killOnExit = (exitingProcess, processesToKill) => { 11 | const handler = () => { 12 | const processes = Array.isArray(processesToKill) ? 13 | processesToKill : [processesToKill]; 14 | 15 | processes.forEach(doomed => doomed.kill('SIGTERM')); 16 | exitingProcess.exit(); 17 | }; 18 | 19 | exitingProcess.on('exit', handler.bind(null)); 20 | exitingProcess.on('SIGTERM', handler.bind(null)); 21 | // catches ctrl+c event 22 | exitingProcess.on('SIGINT', handler.bind(null)); 23 | // catches uncaught exceptions 24 | exitingProcess.on('uncaughtException', handler.bind(null)); 25 | }; 26 | 27 | /** 28 | * When `exitingProcess` exits, receives `SIGINT`, or has an 29 | * uncaught exception, calls the `next` callback 30 | * @param {ChildProcess} exitingProcess - process to watch 31 | * @param {Function} next - callback 32 | */ 33 | export const nextOnExit = (exitingProcess, next) => { 34 | exitingProcess.on('exit', next.bind(null)); 35 | exitingProcess.on('SIGTERM', next.bind(null)); 36 | // catches ctrl+c event 37 | exitingProcess.on('SIGINT', next.bind(null)); 38 | // catches uncaught exceptions 39 | exitingProcess.on('uncaughtException', next.bind(null)); 40 | }; 41 | 42 | /** 43 | * Null object stand-in for a process 44 | * @type {{kill: (function()), on: (function())}} 45 | */ 46 | export const nullProcess = { 47 | kill: noop, 48 | on: noop 49 | }; 50 | -------------------------------------------------------------------------------- /dockerfiles/files/scripts/inject_static_secrets: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | STATIC_PATH=/var/www 4 | ENVVARS=$@ 5 | 6 | function dosub { 7 | VAR_NAME="${1}_VAL" 8 | SANATIZED_VALUE=$(echo ${!VAR_NAME} | sed -e 's/[\/&]/\\&/g') 9 | echo "Replacing $1 in all static content starting at path $STATIC_PATH with contents of $VAR_NAME which is $SANATIZED_VALUE" 10 | find $STATIC_PATH -type f -print0 | LC_ALL=C xargs -0 sed -i "s/${1}_ENV/${SANATIZED_VALUE}/g" 11 | } 12 | 13 | for VAR in "$@"; do 14 | NEW_VALUE=${!VAR} 15 | dosub $VAR $NEW_VALUE 16 | done 17 | -------------------------------------------------------------------------------- /dockerfiles/files/scripts/install_deps_debian.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | . /opt/bridge-gui/scripts/node_setup.sh 4 | apt-get install -y nodejs git make build-essential vim 5 | -------------------------------------------------------------------------------- /dockerfiles/files/scripts/node_setup.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # Discussion, issues and change requests at: 4 | # https://github.com/nodesource/distributions 5 | # 6 | # Script to install the NodeSource Node.js 0.12 repo onto a 7 | # Debian or Ubuntu system. 8 | # 9 | # Run as root or insert `sudo -E` before `bash`: 10 | # 11 | # curl -sL https://deb.nodesource.com/setup_4.x | bash - 12 | # or 13 | # wget -qO- https://deb.nodesource.com/setup_4.x | bash - 14 | # 15 | 16 | export DEBIAN_FRONTEND=noninteractive 17 | 18 | print_status() { 19 | echo 20 | echo "## $1" 21 | echo 22 | } 23 | 24 | bail() { 25 | echo 'Error executing command, exiting' 26 | exit 1 27 | } 28 | 29 | exec_cmd_nobail() { 30 | echo "+ $1" 31 | bash -c "$1" 32 | } 33 | 34 | exec_cmd() { 35 | exec_cmd_nobail "$1" || bail 36 | } 37 | 38 | 39 | print_status "Installing the NodeSource Node.js 4.x repo..." 40 | 41 | 42 | PRE_INSTALL_PKGS="" 43 | 44 | # Check that HTTPS transport is available to APT 45 | # (Check snaked from: https://get.docker.io/ubuntu/) 46 | 47 | if [ ! -e /usr/lib/apt/methods/https ]; then 48 | PRE_INSTALL_PKGS="${PRE_INSTALL_PKGS} apt-transport-https" 49 | fi 50 | 51 | if [ ! -x /usr/bin/lsb_release ]; then 52 | PRE_INSTALL_PKGS="${PRE_INSTALL_PKGS} lsb-release" 53 | fi 54 | 55 | if [ ! -x /usr/bin/curl ] && [ ! -x /usr/bin/wget ]; then 56 | PRE_INSTALL_PKGS="${PRE_INSTALL_PKGS} curl" 57 | fi 58 | 59 | # Populating Cache 60 | print_status "Populating apt-get cache..." 61 | exec_cmd 'apt-get update' 62 | 63 | if [ "X${PRE_INSTALL_PKGS}" != "X" ]; then 64 | print_status "Installing packages required for setup:${PRE_INSTALL_PKGS}..." 65 | # This next command needs to be redirected to /dev/null or the script will bork 66 | # in some environments 67 | exec_cmd "apt-get install -y${PRE_INSTALL_PKGS} > /dev/null 2>&1" 68 | fi 69 | 70 | DISTRO=$(lsb_release -c -s) 71 | 72 | check_alt() { 73 | if [ "X${DISTRO}" == "X${2}" ]; then 74 | echo 75 | echo "## You seem to be using ${1} version ${DISTRO}." 76 | echo "## This maps to ${3} \"${4}\"... Adjusting for you..." 77 | DISTRO="${4}" 78 | fi 79 | } 80 | 81 | check_alt "Kali" "sana" "Debian" "jessie" 82 | check_alt "Debian" "stretch" "Debian" "jessie" 83 | check_alt "Linux Mint" "maya" "Ubuntu" "precise" 84 | check_alt "Linux Mint" "qiana" "Ubuntu" "trusty" 85 | check_alt "Linux Mint" "rafaela" "Ubuntu" "trusty" 86 | check_alt "Linux Mint" "rebecca" "Ubuntu" "trusty" 87 | check_alt "Linux Mint" "rosa" "Ubuntu" "trusty" 88 | check_alt "LMDE" "betsy" "Debian" "jessie" 89 | check_alt "elementaryOS" "luna" "Ubuntu" "precise" 90 | check_alt "elementaryOS" "freya" "Ubuntu" "trusty" 91 | check_alt "Trisquel" "toutatis" "Ubuntu" "precise" 92 | check_alt "Trisquel" "belenos" "Ubuntu" "trusty" 93 | check_alt "BOSS" "anokha" "Debian" "wheezy" 94 | check_alt "bunsenlabs" "bunsen-hydrogen" "Debian" "jessie" 95 | 96 | if [ "X${DISTRO}" == "Xdebian" ]; then 97 | print_status "Unknown Debian-based distribution, checking /etc/debian_version..." 98 | NEWDISTRO=$([ -e /etc/debian_version ] && cut -d/ -f1 < /etc/debian_version) 99 | if [ "X${NEWDISTRO}" == "X" ]; then 100 | print_status "Could not determine distribution from /etc/debian_version..." 101 | else 102 | DISTRO=$NEWDISTRO 103 | print_status "Found \"${DISTRO}\" in /etc/debian_version..." 104 | fi 105 | fi 106 | 107 | print_status "Confirming \"${DISTRO}\" is supported..." 108 | 109 | if [ -x /usr/bin/curl ]; then 110 | exec_cmd_nobail "curl -sLf -o /dev/null 'https://deb.nodesource.com/node_4.x/dists/${DISTRO}/Release'" 111 | RC=$? 112 | else 113 | exec_cmd_nobail "wget -qO /dev/null -o /dev/null 'https://deb.nodesource.com/node_4.x/dists/${DISTRO}/Release'" 114 | RC=$? 115 | fi 116 | 117 | if [[ $RC != 0 ]]; then 118 | print_status "Your distribution, identified as \"${DISTRO}\", is not currently supported, please contact NodeSource at https://github.com/nodesource/distributions/issues if you think this is incorrect or would like your distribution to be considered for support" 119 | exit 1 120 | fi 121 | 122 | if [ -f "/etc/apt/sources.list.d/chris-lea-node_js-$DISTRO.list" ]; then 123 | print_status 'Removing Launchpad PPA Repository for NodeJS...' 124 | 125 | exec_cmd_nobail 'add-apt-repository -y -r ppa:chris-lea/node.js' 126 | exec_cmd "rm -f /etc/apt/sources.list.d/chris-lea-node_js-${DISTRO}.list" 127 | fi 128 | 129 | print_status 'Adding the NodeSource signing key to your keyring...' 130 | 131 | if [ -x /usr/bin/curl ]; then 132 | exec_cmd 'curl -s https://deb.nodesource.com/gpgkey/nodesource.gpg.key | apt-key add -' 133 | else 134 | exec_cmd 'wget -qO- https://deb.nodesource.com/gpgkey/nodesource.gpg.key | apt-key add -' 135 | fi 136 | 137 | print_status 'Creating apt sources list file for the NodeSource Node.js 4.x repo...' 138 | 139 | exec_cmd "echo 'deb https://deb.nodesource.com/node_4.x ${DISTRO} main' > /etc/apt/sources.list.d/nodesource.list" 140 | exec_cmd "echo 'deb-src https://deb.nodesource.com/node_4.x ${DISTRO} main' >> /etc/apt/sources.list.d/nodesource.list" 141 | 142 | print_status 'Running `apt-get update` for you...' 143 | 144 | exec_cmd 'apt-get update' 145 | 146 | print_status 'Run `apt-get install nodejs` (as root) to install Node.js 4.x and npm' 147 | -------------------------------------------------------------------------------- /dockerfiles/files/scripts/start-bridge-gui: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # On build, variables are set to contain [VAR_NAME]_ENV 4 | # The dist build happens and the bridge-gui app puts the "[VAR_NAME]_ENV" values in the compiled source 5 | # On run, the inject script (scripts/inject_static_secrets.sh) replaces "[VAR_NAME]_ENV" with 6 | # the variables defined in [VAR_NAME]_VAL if defined or [VAR_NAME]_DEFAULT if not 7 | 8 | # Set the config replacement values if we have an ENV var set for it 9 | # otherwise, use the default 10 | export NODE_ENV_VAL="${NODE_ENV_VAL:-$NODE_ENV_DEFAULT}" 11 | export STRIPE_PUBLISHABLE_KEY_VAL="${STRIPE_PUBLISHABLE_KEY_VAL:-$STRIPE_PUBLISHABLE_KEY_DEFAULT}" 12 | export BILLING_URL_VAL="${BILLING_URL_VAL:-$BILLING_URL_DEFAULT}" 13 | export BRIDGE_URL_VAL="${BRIDGE_URL_VAL:-$BRIDGE_URL_DEFAULT}" 14 | 15 | # Replace params in static content with desired values 16 | echo "Injecting secrets into Statically generated content" 17 | . /usr/local/bin/inject_static_secrets \ 18 | NODE_ENV \ 19 | STRIPE_PUBLISHABLE_KEY \ 20 | BILLING_URL \ 21 | BRIDGE_URL 22 | 23 | touch /var/www/.env 24 | echo "NODE_ENV=$NODE_ENV_VAL" >> /var/www/.env 25 | echo "STRIPE_PUBLISHABLE_KEY=$STRIPE_PUBLISHABLE_KEY_VAL" >> /var/www/.env 26 | echo "BILLING_URL=$BILLING_URL_VAL" >> /var/www/.env 27 | echo "BRIDGE_URL=$BRIDGE_URL_VAL" >> /var/www/.env 28 | 29 | # Start Nginx to serve Bridge GUI 30 | echo "Serving Bridge GUI through Nginx" 31 | 32 | /usr/sbin/nginx 33 | -------------------------------------------------------------------------------- /dockerfiles/push.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | for TAG in "$@"; do 4 | docker push $TAG 5 | result=$? 6 | done 7 | 8 | if [[ $result != 0 ]]; then 9 | echo "Error pushing docker image" 10 | exit 1 11 | fi 12 | 13 | echo "Success..." 14 | echo 0 15 | -------------------------------------------------------------------------------- /dockerfiles/serve.dockerfile: -------------------------------------------------------------------------------- 1 | # 2 | # Based on https://github.com/KyleAMathews/docker-nginx 3 | # 4 | FROM kyma/docker-nginx 5 | 6 | COPY ./dist /var/www/ 7 | 8 | # Used only for testing with ssl 9 | #COPY ./files/configs/nginx-default-ssl /etc/nginx/sites-available/default-ssl 10 | #RUN ln -s /etc/nginx/sites-available/default-ssl /etc/nginx/sites-enabled 11 | 12 | COPY ./dockerfiles/files/configs/nginx-default /etc/nginx/sites-available/default 13 | RUN rm /etc/nginx/sites-enabled/default 14 | RUN ln -s /etc/nginx/sites-available/default /etc/nginx/sites-enabled/default 15 | COPY ./dockerfiles/files/scripts/inject_static_secrets /usr/local/bin/inject_static_secrets 16 | COPY ./dockerfiles/files/scripts/start-bridge-gui /usr/local/bin/start-bridge-gui 17 | 18 | WORKDIR /etc/nginx 19 | 20 | CMD ["/usr/local/bin/start-bridge-gui"] 21 | -------------------------------------------------------------------------------- /index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | Storj 8 | 9 | 10 | 11 | 16 | 17 |
18 | 19 | 20 | 21 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "bridge-gui-vue", 3 | "version": "1.1.0", 4 | "description": "A web-based GUI for Storj Bridge", 5 | "author": "Barbara Liau ", 6 | "private": true, 7 | "repository": { 8 | "type": "git", 9 | "url": "https://github.com/Storj/bridge-gui-vue" 10 | }, 11 | "license": "AGPL-3.0", 12 | "homepage": "https://app.storj.io", 13 | "scripts": { 14 | "start": "if [[ ${NODE_ENV} == \"development\" ]]; then npm run start:dev; else npm run build; fi", 15 | "start:dev": "node build/dev-server.js", 16 | "dev-w": "webpack --config build/webpack.dev.vm.conf.js --watch", 17 | "build": "node build/build.js", 18 | "unit": "cross-env BABEL_ENV=test karma start test/unit/karma.conf.js --single-run", 19 | "e2e": "node test/e2e/runner.js", 20 | "test": "npm run unit && npm run e2e", 21 | "lint": "eslint --ext .js,.vue src test/unit/specs test/e2e/specs" 22 | }, 23 | "dependencies": { 24 | "axios": "^0.15.3", 25 | "bluebird": "^3.4.7", 26 | "body-parser": "^1.17.1", 27 | "bootstrap": "^4.0.0-alpha.6", 28 | "bootstrap-vue": "^1.3.0", 29 | "compression": "^1.6.2", 30 | "crypto": "0.0.3", 31 | "dotenv-webpack": "^1.4.3", 32 | "lodash": "^4.17.4", 33 | "moment": "^2.18.1", 34 | "qrcode.vue": "^1.5.1", 35 | "qs": "^6.4.0", 36 | "storj-service-error-types": "^1.1.0", 37 | "uuid": "^3.0.1", 38 | "vue": "^2.3.0", 39 | "vue-awesome": "^2.3.4", 40 | "vue-clipboards": "^0.2.6", 41 | "vue-router": "^2.5.2", 42 | "vuex": "^2.3.0", 43 | "vuex-router-sync": "^4.1.0" 44 | }, 45 | "devDependencies": { 46 | "autoprefixer": "^6.7.7", 47 | "babel-core": "^6.24.0", 48 | "babel-eslint": "^7.2.1", 49 | "babel-loader": "^6.4.1", 50 | "babel-plugin-istanbul": "^3.1.2", 51 | "babel-plugin-transform-object-rest-spread": "^6.23.0", 52 | "babel-plugin-transform-runtime": "^6.22.0", 53 | "babel-preset-babili": "0.0.12", 54 | "babel-preset-env": "^1.4.0", 55 | "babel-preset-stage-2": "^6.22.0", 56 | "babel-register": "^6.24.0", 57 | "babili-webpack-plugin": "0.0.11", 58 | "chai": "^3.5.0", 59 | "chalk": "^1.1.3", 60 | "chromedriver": "^2.28.0", 61 | "connect-history-api-fallback": "^1.3.0", 62 | "copy-webpack-plugin": "^4.0.1", 63 | "cross-env": "^3.1.4", 64 | "cross-spawn": "^5.0.1", 65 | "css-loader": "^0.26.2", 66 | "eslint": "^3.14.1", 67 | "eslint-config-standard": "^6.2.1", 68 | "eslint-friendly-formatter": "^2.0.7", 69 | "eslint-loader": "^1.7.0", 70 | "eslint-plugin-html": "^2.0.0", 71 | "eslint-plugin-promise": "^3.5.0", 72 | "eslint-plugin-standard": "^2.1.1", 73 | "eventsource-polyfill": "^0.9.6", 74 | "express": "^4.15.2", 75 | "extract-text-webpack-plugin": "^2.0.0", 76 | "file-loader": "^0.10.0", 77 | "friendly-errors-webpack-plugin": "^1.1.3", 78 | "function-bind": "^1.1.0", 79 | "html-webpack-plugin": "^2.28.0", 80 | "http-proxy-middleware": "^0.17.4", 81 | "inject-loader": "^2.0.1", 82 | "karma": "^1.4.1", 83 | "karma-coverage": "^1.1.1", 84 | "karma-mocha": "^1.3.0", 85 | "karma-phantomjs-launcher": "^1.0.2", 86 | "karma-sinon-chai": "^1.2.4", 87 | "karma-sourcemap-loader": "^0.3.7", 88 | "karma-spec-reporter": "0.0.26", 89 | "karma-webpack": "^2.0.2", 90 | "lolex": "^1.5.2", 91 | "mocha": "^3.2.0", 92 | "nightwatch": "^0.9.14", 93 | "node-sass": "^4.5.0", 94 | "opn": "^4.0.2", 95 | "optimize-css-assets-webpack-plugin": "^1.3.0", 96 | "ora": "^1.1.0", 97 | "phantomjs-prebuilt": "^2.1.14", 98 | "rimraf": "^2.6.0", 99 | "sass-loader": "^6.0.2", 100 | "selenium-server": "^3.0.1", 101 | "semver": "^5.3.0", 102 | "shebang-loader": "0.0.1", 103 | "sinon": "^1.17.7", 104 | "sinon-chai": "^2.8.0", 105 | "url-loader": "^0.5.7", 106 | "vue-loader": "^12.0.2", 107 | "vue-style-loader": "^3.0.1", 108 | "vue-template-compiler": "^2.3.0", 109 | "webpack": "^2.4.1", 110 | "webpack-bundle-analyzer": "^2.2.1", 111 | "webpack-dashboard": "^1.0.0-5", 112 | "webpack-dev-middleware": "^1.10.0", 113 | "webpack-hot-middleware": "^2.16.1", 114 | "webpack-merge": "^2.6.1" 115 | }, 116 | "engines": { 117 | "node": ">= 6.9.5", 118 | "npm": ">= 3.10.0" 119 | } 120 | } 121 | -------------------------------------------------------------------------------- /src/App.vue: -------------------------------------------------------------------------------- 1 | 16 | 17 | 22 | 23 | 24 | 25 | 32 | -------------------------------------------------------------------------------- /src/api/billing-client.js: -------------------------------------------------------------------------------- 1 | import axios from 'axios'; 2 | import config from '../../config'; 3 | import Client from './client'; 4 | 5 | const billingClient = new Client({ 6 | baseURL: config.app.BILLING_URL, 7 | bridgeURL: config.app.BRIDGE_URL, 8 | httpClient: axios 9 | }); 10 | 11 | export default billingClient; 12 | -------------------------------------------------------------------------------- /src/api/bridge-client.js: -------------------------------------------------------------------------------- 1 | import axios from 'axios'; 2 | import config from '../../config'; 3 | import Client from './client'; 4 | 5 | const bridgeClient = new Client({ 6 | baseURL: config.app.BRIDGE_URL, 7 | bridgeURL: config.app.BRIDGE_URL, 8 | httpClient: axios 9 | }); 10 | 11 | export default bridgeClient; 12 | -------------------------------------------------------------------------------- /src/api/client.js: -------------------------------------------------------------------------------- 1 | import { lStorage } from '@/utils'; 2 | import uuid from 'uuid/v4'; 3 | import Storj from '../../vendors/storj.es6'; 4 | import qs from 'qs'; 5 | import Promise from 'bluebird'; 6 | 7 | /** 8 | * @params {String} opts.baseURL - baseURL for API i.e. https://api.storj.io 9 | * @params {String} opts.bridgeURL - bridgeURL for Storj Bridge. May or may not be 10 | * the same as baseURL. i.e. https://api.storj.io 11 | * @params {Object} opts.httpClient - your choice of client to make http calls 12 | * (i.e. axios, ajax) 13 | * 14 | * Reference: https://github.com/Storj/bridge/blob/main/doc/auth.md 15 | */ 16 | 17 | class Client { 18 | constructor ({ baseURL, bridgeURL, httpClient }) { 19 | this._baseURL = baseURL; 20 | this._bridgeURL = bridgeURL; 21 | this._httpClient = httpClient; 22 | } 23 | 24 | /** 25 | * Authenticates requests sent to Storj clients. 26 | * @params {String} method - HTTP method ('GET', 'POST', 'PUT') 27 | * @params {String} path - Path for HTTP request 28 | * @params {Object} params - data for requests 29 | * @params {Object} credentials - basic auth credentials 30 | * Example usage: 31 | * client.request('GET', '/credits/test') 32 | * 33 | */ 34 | request (method, path, params = {}, credentials = {}) { 35 | return new Promise((resolve, reject) => { 36 | const privateKey = credentials.privateKey || lStorage.retrieve('privateKey'); 37 | const isGetOrDel = ['GET', 'DELETE'].indexOf(method) !== -1 || false; 38 | 39 | // Nonce for signing up 40 | const nonce = uuid(); 41 | params.__nonce = nonce; 42 | 43 | const baseOpts = { 44 | baseURL: this._baseURL, 45 | method: method.toLowerCase(), 46 | protocol: 'https' 47 | }; 48 | 49 | if (isGetOrDel) { 50 | baseOpts.qs = params; 51 | } else { 52 | baseOpts.data = params; 53 | } 54 | 55 | const authOpts = privateKey 56 | ? this._ecdsa(method, path, params, privateKey, isGetOrDel) 57 | : this._basicAuth(method, path, params, credentials, isGetOrDel); 58 | 59 | const opts = Object.assign(baseOpts, authOpts); 60 | 61 | return this._httpClient(opts) 62 | .then((result) => resolve(result)) 63 | .catch((err) => { 64 | reject(err); 65 | }); 66 | }); 67 | } 68 | 69 | _ecdsa (method, path, params, privateKey, isGetOrDel) { 70 | const storj = new Storj({ 71 | bridge: this._bridgeURL, 72 | key: privateKey, 73 | protocol: 'https' 74 | }); 75 | 76 | const keypair = storj.generateKeyPair(privateKey); 77 | const publicKey = keypair.getPublicKey(); 78 | 79 | // Stringify according to type of request 80 | const payload = isGetOrDel ? qs.stringify(params) : JSON.stringify(params); 81 | 82 | // Create contract string in format of \n\n 83 | const contract = [method, path, payload].join('\n'); 84 | 85 | // Sign contract with keypair 86 | const signedContract = keypair.sign(contract, { compact: false }); 87 | 88 | const query = isGetOrDel ? `?${payload}` : ``; 89 | const opts = { 90 | url: path + query, 91 | headers: { 92 | 'x-pubkey': publicKey, 93 | 'x-signature': signedContract 94 | } 95 | }; 96 | 97 | return opts; 98 | } 99 | 100 | _basicAuth (method, path, params, credentials, isGetOrDel) { 101 | const query = isGetOrDel ? `?${qs.stringify(params)}` : ``; 102 | const opts = { 103 | url: path + query, 104 | auth: { 105 | user: credentials.email, 106 | pass: credentials.password 107 | } 108 | }; 109 | return opts; 110 | } 111 | } 112 | 113 | export default Client; 114 | -------------------------------------------------------------------------------- /src/components/Message-Page.vue: -------------------------------------------------------------------------------- 1 | 11 | 12 | 22 | 23 | 25 | -------------------------------------------------------------------------------- /src/components/Nav-Authentication.vue: -------------------------------------------------------------------------------- 1 | 14 | 15 | 20 | 21 | 27 | -------------------------------------------------------------------------------- /src/components/Sj-Crypto-Payment-Btn.vue: -------------------------------------------------------------------------------- 1 | 53 | 54 | 98 | 99 | 130 | -------------------------------------------------------------------------------- /src/components/Sj-Go-Back-Btn.vue: -------------------------------------------------------------------------------- 1 | 7 | 8 | 24 | 25 | 29 | -------------------------------------------------------------------------------- /src/components/Sj-Loading.vue: -------------------------------------------------------------------------------- 1 | 13 | 14 | 38 | 39 | 41 | -------------------------------------------------------------------------------- /src/config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | // Don't need any of the config vars from bridge-gui because none of this 3 | // is server-side rendered 4 | // dev server is for hot reloading 5 | BRIDGE_URL: process.env.NODE_ENV === 'development' 6 | ? 'http://bridge-ssl-proxy' : process.env.BRIDGE_URL, 7 | BILLING_URL: process.env.NODE_ENV === 'development' 8 | ? 'localhost:3000/graphql' : process.env.BILLING_URL, 9 | RESET_PASSWORD_REDIRECT_URL: process.env.NODE_ENV === 'development' 10 | ? 'https://app.staging.storj.io' 11 | : 'https://app.storj.io' 12 | }; 13 | -------------------------------------------------------------------------------- /src/filters/index.js: -------------------------------------------------------------------------------- 1 | import moment from 'moment'; 2 | 3 | export const prettifyAmount = function (amount) { 4 | if (typeof (amount) !== 'number') { 5 | return '0.00'; 6 | } 7 | 8 | const modAmount = (amount / 100).toFixed(6); 9 | 10 | // Handles any 0.000000 debits 11 | if (modAmount.indexOf('0.000000') === 0) { 12 | return '0.00'; 13 | } 14 | 15 | // Trims zeros if all are 6 16 | if (modAmount.substr(-6) === '000000') { 17 | const setToTwoPlaces = (amount / 100).toFixed(2); 18 | return setToTwoPlaces; 19 | } 20 | 21 | // Return all the decimal places if it's less than $1 22 | // Looks weird otherwise 23 | if (modAmount.indexOf('0.') === 0) { 24 | return modAmount; 25 | } 26 | 27 | // Otherwise, if amount is > $1, then trim the zeros 28 | const trimmedAmount = trimOffZeros(modAmount); 29 | 30 | return trimmedAmount; 31 | }; 32 | 33 | function trimOffZeros (amount) { 34 | const trimmed = amount.toString().replace(/0+$/, ''); 35 | 36 | if (trimmed.substr(-1) === '.') { 37 | const addTwoZeros = trimmed.concat('00'); 38 | return addTwoZeros; 39 | } 40 | 41 | return trimmed; 42 | } 43 | 44 | export const addDollarSign = function (amount) { 45 | if (amount.indexOf('-') === 0) { 46 | var modAmount = amount.slice(1, amount.length); 47 | return `-$${modAmount}`; 48 | } 49 | return `$${amount}`; 50 | }; 51 | 52 | export const dateFormat = function (date, formatType) { 53 | switch (formatType) { 54 | case 'long': 55 | return `${moment.utc((date)).format('MMM DD, YYYY - HH:mm')} UTC`; 56 | 57 | default: 58 | return `${moment.utc((date)).format('MMM DD, YYYY - HH:mm')} UTC`; 59 | } 60 | }; 61 | 62 | /** 63 | * Adds ordinal suffixes to date and stringifies 64 | * @param {Number} date - only the day date, 1, 2, ... 31, etc. 65 | * @returns {String} - date with ordinal suffix 66 | */ 67 | export const dateSuffix = function (date) { 68 | const nd = [ 2, 22 ]; 69 | const st = [ 1, 21, 31 ]; 70 | const th = [ 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 71 | 20, 24, 25, 26, 27, 28, 29, 30 ]; 72 | const rd = [ 3, 23 ]; 73 | 74 | if (th.indexOf(date) !== -1) { 75 | return `${date}th`; 76 | } 77 | 78 | if (st.indexOf(date) !== -1) { 79 | return `${date}st`; 80 | } 81 | 82 | if (nd.indexOf(date) !== -1) { 83 | return `${date}nd`; 84 | } 85 | 86 | if (rd.indexOf(date) !== -1) { 87 | return `${date}rd`; 88 | } 89 | }; 90 | 91 | export const capitalize = function (str) { 92 | return str.replace(/^\w/, (w) => (w.toUpperCase())); 93 | }; 94 | -------------------------------------------------------------------------------- /src/main.js: -------------------------------------------------------------------------------- 1 | // The Vue build version to load with the `import` command 2 | // (runtime-only or standalone) has been set in webpack.base.conf with an alias. 3 | import Vue from 'vue'; 4 | import App from './App'; 5 | import * as filters from './filters'; 6 | import store from './store'; 7 | import router from './router'; 8 | import { sync } from 'vuex-router-sync'; 9 | 10 | import Icon from 'vue-awesome/components/Icon'; 11 | import VueClipboards from 'vue-clipboards'; 12 | // ES build is more efficient by reducing unneeded components with tree-shaking. 13 | // (Needs Webpack 2 or Rollup) 14 | import BootstrapVue from 'bootstrap-vue/dist/bootstrap-vue.esm'; 15 | 16 | // Import styles 17 | import 'bootstrap/dist/css/bootstrap.css'; 18 | import 'bootstrap-vue/dist/bootstrap-vue.css'; 19 | 20 | // Globally register components 21 | Vue.use(BootstrapVue); 22 | Vue.use(VueClipboards); 23 | Vue.component('icon', Icon); 24 | // sync the router with the vuex store. 25 | // this registers `store.state.route` 26 | sync(store, router); 27 | 28 | // register global utility filters. 29 | Object.keys(filters).forEach(key => { 30 | Vue.filter(key, filters[key]); 31 | }); 32 | 33 | // create the app instance. 34 | // here we inject the router and store to all child components, 35 | // making them available everywhere as `this.$router` and `this.$store`. 36 | const app = new Vue({ 37 | router, 38 | store, 39 | ...App 40 | }); 41 | 42 | // actually mount to DOM 43 | app.$mount('#app'); 44 | -------------------------------------------------------------------------------- /src/router/index.js: -------------------------------------------------------------------------------- 1 | import Vue from 'vue'; 2 | import Router from 'vue-router'; 3 | import Login from '@/views/Login'; 4 | // import Signup from '@/views/Signup'; 5 | import PasswordReset from '@/views/Password-Reset'; 6 | import PasswordSet from '@/views/Password-Reset/password-set'; 7 | import NotFound from '@/views/Not-Found'; 8 | import Dashboard from '@/views/Dashboard'; 9 | import Buckets from '@/views/Buckets'; 10 | import BucketList from '@/views/Buckets/Bucket-List'; 11 | import CreateBucket from '@/views/Buckets/Create-Bucket'; 12 | // import BucketSettings from '@/views/Buckets/Bucket-Settings'; 13 | import BucketFiles from '@/views/Buckets/Bucket-Files'; 14 | import Support from '@/views/Support'; 15 | import Billing from '@/views/Billing'; 16 | import Settings from '@/views/Settings'; 17 | import Referrals from '@/views/Referrals'; 18 | import { lStorage } from '@/utils'; 19 | // import analytics from '@/vendors/analytics'; 20 | 21 | Vue.use(Router); 22 | 23 | const router = new Router({ 24 | mode: 'history', 25 | scrollBehavior: () => ({ y: 0 }), 26 | routes: [ 27 | /* Open Authentication Routes */ 28 | { 29 | path: '/login', 30 | name: 'Login', 31 | component: Login 32 | }, 33 | // { 34 | // path: '/signup', 35 | // name: 'Signup', 36 | // component: Signup 37 | // }, 38 | { 39 | path: '/password-reset', 40 | name: 'Password-Reset', 41 | component: PasswordReset 42 | }, 43 | { 44 | path: '/resets/:token', 45 | name: 'Password-Set', 46 | component: PasswordSet 47 | }, 48 | /* Dashboard - requires authenticated user */ 49 | { 50 | path: '/dashboard', 51 | redirect: '/dashboard/billing', 52 | name: 'Dashboard', 53 | component: Dashboard, 54 | meta: { requiresAuth: true }, 55 | children: [ 56 | { 57 | path: 'buckets', 58 | component: Buckets, 59 | children: [ 60 | { 61 | // root bucket path 62 | path: '/', 63 | name: 'Buckets', 64 | component: BucketList 65 | }, 66 | { 67 | path: 'create', 68 | name: 'Create Bucket', 69 | component: CreateBucket 70 | }, 71 | // NB: No settings until updateBucketById is added to storj.js 72 | // { 73 | // path: ':bucketId/settings', 74 | // name: 'Bucket Settings', 75 | // component: BucketSettings 76 | // }, 77 | { 78 | path: ':bucketId/files', 79 | name: 'Bucket Files', 80 | component: BucketFiles 81 | } 82 | ] 83 | }, 84 | { 85 | path: 'support', 86 | name: 'Support', 87 | component: Support 88 | }, 89 | { 90 | path: 'billing', 91 | name: 'Billing', 92 | component: Billing 93 | }, 94 | { 95 | path: 'referrals', 96 | name: 'Referrals', 97 | component: Referrals 98 | }, 99 | { 100 | path: 'settings', 101 | name: 'Settings', 102 | component: Settings 103 | } 104 | ] 105 | }, 106 | { 107 | path: '/', 108 | redirect: '/login' 109 | }, 110 | { 111 | path: '/not-found', 112 | name: 'Not-Found', 113 | component: NotFound 114 | }, 115 | { 116 | path: '*', 117 | redirect: '/not-found' 118 | } 119 | ] 120 | }); 121 | 122 | router.beforeEach((to, from, next) => { 123 | if (to.matched.some((record) => record.meta.requiresAuth)) { 124 | const privateKey = lStorage.retrieve('privateKey'); 125 | 126 | if (!privateKey) { 127 | return next({ path: '/login' }); 128 | } 129 | 130 | next(); 131 | } else { 132 | next(); 133 | } 134 | }); 135 | 136 | export default router; 137 | -------------------------------------------------------------------------------- /src/store/actions.js: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/storj-archived/bridge-gui-vue/337a410f73fd46e132bf11ab0a7b201908d78ca2/src/store/actions.js -------------------------------------------------------------------------------- /src/store/getters.js: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/storj-archived/bridge-gui-vue/337a410f73fd46e132bf11ab0a7b201908d78ca2/src/store/getters.js -------------------------------------------------------------------------------- /src/store/index.js: -------------------------------------------------------------------------------- 1 | import Vue from 'vue'; 2 | import Vuex from 'vuex'; 3 | import * as actions from './actions'; 4 | import user from './modules/user'; 5 | import keypair from './modules/keypair'; 6 | import buckets from './modules/buckets'; 7 | import auth from './modules/auth'; 8 | import billing from './modules/billing'; 9 | import marketing from './modules/marketing'; 10 | 11 | Vue.use(Vuex); 12 | 13 | const debug = process.env.NODE_ENV !== 'production'; 14 | 15 | export default new Vuex.Store({ 16 | actions, 17 | modules: { 18 | auth, 19 | user, 20 | keypair, 21 | buckets, 22 | billing, 23 | marketing 24 | }, 25 | strict: debug, 26 | plugins: [] 27 | }); 28 | -------------------------------------------------------------------------------- /src/store/modules/auth.js: -------------------------------------------------------------------------------- 1 | import Promise from 'bluebird'; 2 | import { 3 | SET_AUTHENTICATION, 4 | SET_USER, 5 | CLEAR_USER, 6 | CLEAR_KEYS, 7 | CLEAR_BILLING, 8 | CLEAR_MARKETING 9 | } from '../mutation-types'; 10 | import config from '../../../config'; 11 | import errors from 'storj-service-error-types'; 12 | import Storj from '../../../vendors/storj.es6'; 13 | import axios from 'axios'; 14 | 15 | const state = { 16 | authenticated: false 17 | }; 18 | 19 | const mutations = { 20 | [SET_AUTHENTICATION] (state, authenticated) { 21 | state.authenticated = authenticated; 22 | } 23 | }; 24 | 25 | const actions = { 26 | authenticateAll ({ commit }, email) { 27 | if (email) { 28 | commit(SET_USER, email); 29 | } 30 | commit(SET_AUTHENTICATION, true); 31 | }, 32 | 33 | unauthenticateAll ({ commit, rootState }) { 34 | commit(SET_AUTHENTICATION, false); 35 | commit(CLEAR_USER); 36 | commit(CLEAR_KEYS); 37 | commit(CLEAR_BILLING); 38 | commit(CLEAR_MARKETING); 39 | }, 40 | 41 | login ({ commit, dispatch }, credentials) { 42 | return new Promise((resolve, reject) => { 43 | dispatch('basicAuth', credentials).then((storj) => { 44 | return dispatch('unregisterKey', storj) 45 | .then(() => dispatch('generateKeypair', storj)) 46 | .then((keypair) => { 47 | return dispatch('registerKey', { 48 | publicKey: keypair.getPublicKey(), 49 | storj: storj 50 | }) 51 | .then(() => resolve()) 52 | .catch((err) => reject(err)); 53 | }) 54 | .catch((err) => reject(err)); 55 | }).catch((err) => reject(err)); 56 | }); 57 | }, 58 | 59 | logout ({ commit, dispatch }) { 60 | return new Promise((resolve, reject) => { 61 | dispatch('keypairAuth') 62 | .then((storj) => dispatch('unregisterKey', storj)) 63 | .then(() => { 64 | dispatch('unauthenticateAll'); 65 | return resolve(); 66 | }) 67 | .catch(() => { 68 | dispatch('unauthenticateAll'); 69 | return reject(); 70 | }); 71 | }); 72 | }, 73 | 74 | /* 75 | * #resetPassword 76 | */ 77 | resetPassword ({ commit, dispatch }, credentials) { 78 | return new Promise((resolve, reject) => { 79 | axios 80 | .patch(`${config.app.BRIDGE_URL}/users/${credentials.email}`, credentials) 81 | .then(() => resolve()) 82 | .catch((err) => reject(err)); 83 | }); 84 | }, 85 | 86 | /* 87 | * #confirmPasswordReset - sends the hashed password and a reset token 88 | * to the bridge. 89 | * - password: SHA-256 hash of password 90 | * - token: reset token user received from email 91 | */ 92 | confirmPasswordReset ({ commit }, { password, token }) { 93 | return axios 94 | .post(`${config.app.BRIDGE_URL}/resets/${token}`, { 95 | password 96 | }) 97 | .then((res) => console.log(res)) 98 | .catch((err) => console.error(err)); 99 | }, 100 | 101 | /** 102 | * Verifies Storj is authenticated until an isAuthenticated method is 103 | * implemented on storj.js 104 | */ 105 | isStorjAuthenticated ({ commit, dispatch }, storj) { 106 | return new Promise((resolve, reject) => { 107 | if (!storj) { 108 | return reject(new errors.BadRequestError('No Storj instance')); 109 | } 110 | 111 | storj.getKeyList(function (err) { 112 | if (err) { 113 | return reject(err); 114 | } 115 | return resolve(true); 116 | }); 117 | }); 118 | }, 119 | 120 | basicAuth ({ commit, dispatch }, credentials) { 121 | return new Promise((resolve, reject) => { 122 | const options = { 123 | bridge: config.app.BRIDGE_URL, 124 | basicAuth: credentials 125 | }; 126 | 127 | const storj = new Storj(options); 128 | 129 | storj.on('ready', function () { 130 | dispatch('isStorjAuthenticated', storj) 131 | .then(() => { 132 | dispatch('authenticateAll', credentials.email); 133 | return resolve(storj); 134 | }) 135 | .catch((err) => { 136 | dispatch('unauthenticateAll'); 137 | return reject(err); 138 | }); 139 | }); 140 | }); 141 | }, 142 | 143 | keypairAuth ({ commit, dispatch, rootState }) { 144 | return new Promise((resolve, reject) => { 145 | const privateKey = rootState.keypair.privateKey; 146 | 147 | if (!privateKey) { 148 | return reject('No private key'); 149 | } 150 | 151 | const options = { 152 | bridge: config.app.BRIDGE_URL, 153 | key: privateKey 154 | }; 155 | 156 | const storj = new Storj(options); 157 | 158 | storj.on('ready', function () { 159 | return resolve(storj); 160 | }); 161 | 162 | storj.on('error', function (err) { 163 | return reject(err); 164 | }); 165 | }); 166 | } 167 | }; 168 | 169 | export default { 170 | state, 171 | mutations, 172 | actions 173 | }; 174 | -------------------------------------------------------------------------------- /src/store/modules/buckets.js: -------------------------------------------------------------------------------- 1 | /* eslint no-undef: ["error", { "typeof": false }] */ 2 | import errors from 'storj-service-error-types'; 3 | import Promise from 'bluebird'; 4 | import { 5 | SET_BUCKETS, 6 | ADD_BUCKET, 7 | SET_CURRENT_BUCKET_META, 8 | SET_CURRENT_BUCKET_FILES, 9 | CLEAR_BUCKET_STATE 10 | } from '../mutation-types'; 11 | 12 | const state = { 13 | all: [], 14 | current: { 15 | meta: {}, 16 | files: [] 17 | } 18 | }; 19 | 20 | const mutations = { 21 | [SET_BUCKETS] (state, buckets) { 22 | state.all = buckets; 23 | }, 24 | 25 | [ADD_BUCKET] (state, bucket) { 26 | const newBucketList = state.all.concat([bucket]); 27 | state.all = newBucketList; 28 | }, 29 | 30 | [SET_CURRENT_BUCKET_META] (state, bucket) { 31 | state.current.meta = bucket; 32 | }, 33 | 34 | [SET_CURRENT_BUCKET_FILES] (state, files) { 35 | state.current.files = files; 36 | }, 37 | 38 | [CLEAR_BUCKET_STATE] (state) { 39 | state.all = []; 40 | state.current.meta = {}; 41 | state.current.files = []; 42 | } 43 | }; 44 | 45 | const actions = { 46 | getBuckets ({ commit, state, dispatch, rootState }) { 47 | return new Promise((resolve, reject) => { 48 | dispatch('keypairAuth').then((storj) => { 49 | storj.getBucketList(function (err, buckets) { 50 | if (err) { 51 | return reject(err); 52 | } 53 | commit(SET_BUCKETS, buckets); 54 | return resolve(); 55 | }); 56 | }).catch((err) => reject(err)); 57 | }); 58 | }, 59 | 60 | createBucket ({ commit, state, dispatch }, bucketName) { 61 | return new Promise((resolve, reject) => { 62 | dispatch('keypairAuth').then((storj) => { 63 | storj.createBucket(bucketName, function (err, bucket) { 64 | if (err) { 65 | return reject(new errors.InternalError(err.message)); 66 | } 67 | commit(SET_CURRENT_BUCKET_META, bucket); 68 | return resolve(bucket.id); 69 | }); 70 | }).catch((err) => reject(new errors.InternalError(err))); 71 | }); 72 | }, 73 | 74 | getBucket ({ commit, state, dispatch }, bucketId) { 75 | return new Promise((resolve, reject) => { 76 | if (!bucketId) { 77 | return reject(new errors.BadRequestError('No bucket ID')); 78 | } 79 | 80 | dispatch('keypairAuth').then((storj) => { 81 | storj.getBucket(bucketId, function (err, bucket) { 82 | if (err) { 83 | return reject(new errors.InternalError(err)); 84 | } 85 | commit(SET_CURRENT_BUCKET_META, bucket); 86 | return resolve(bucket); 87 | }); 88 | }).catch((err) => reject(new errors.InternalError(err))); 89 | }); 90 | }, 91 | 92 | getFileList ({ commit, state, dispatch }, bucketId) { 93 | return new Promise((resolve, reject) => { 94 | if (!bucketId) { 95 | return reject(new errors.BadRequestError('No bucket ID')); 96 | } 97 | 98 | dispatch('keypairAuth').then((storj) => { 99 | storj.getFileList(bucketId, function (err, files) { 100 | if (err) { 101 | return reject(new errors.InternalError(err)); 102 | } 103 | commit(SET_CURRENT_BUCKET_FILES, files); 104 | return resolve(files); 105 | }); 106 | }).catch((err) => reject(new errors.InternalError(err))); 107 | }); 108 | }, 109 | 110 | deleteBucket ({ commit, state, dispatch }, bucketId) { 111 | return new Promise((resolve, reject) => { 112 | if (!bucketId) { 113 | return reject(new errors.BadRequestError('No bucket ID')); 114 | } 115 | 116 | dispatch('keypairAuth').then((storj) => { 117 | storj.deleteBucket(bucketId, function (err) { 118 | if (err) { 119 | return reject(err); 120 | } 121 | commit(SET_CURRENT_BUCKET_META, {}); 122 | commit(SET_CURRENT_BUCKET_FILES, []); 123 | 124 | return resolve(); 125 | }); 126 | }).catch((err) => reject(err)); 127 | }); 128 | } 129 | }; 130 | 131 | export default { 132 | state, 133 | mutations, 134 | actions 135 | }; 136 | -------------------------------------------------------------------------------- /src/store/modules/keypair.js: -------------------------------------------------------------------------------- 1 | /* eslint no-undef: ["error", { "typeof": false }] */ 2 | 3 | import { 4 | SET_PRIVATE_KEY, 5 | SET_PUBLIC_KEY, 6 | CLEAR_KEYS 7 | } from '@/store/mutation-types'; 8 | import errors from 'storj-service-error-types'; 9 | import Promise from 'bluebird'; 10 | import { lStorage } from '@/utils'; 11 | 12 | const state = { 13 | privateKey: lStorage.retrieve('privateKey'), 14 | publicKey: lStorage.retrieve('publicKey') 15 | }; 16 | 17 | const mutations = { 18 | /** 19 | * Saves private key to store and also sets it on Local Storage 20 | */ 21 | [SET_PRIVATE_KEY] (state, privateKey) { 22 | state.privateKey = privateKey; 23 | 24 | lStorage.save('privateKey', privateKey); 25 | }, 26 | 27 | [SET_PUBLIC_KEY] (state, publicKey) { 28 | state.publicKey = publicKey; 29 | 30 | lStorage.save('publicKey', publicKey); 31 | }, 32 | 33 | [CLEAR_KEYS] (state) { 34 | state.privateKey = ''; 35 | state.publicKey = ''; 36 | 37 | lStorage.remove('privateKey'); 38 | lStorage.remove('publicKey'); 39 | } 40 | }; 41 | 42 | const actions = { 43 | generateKeypair ({ commit, state, rootState }, storj) { 44 | return new Promise((resolve, reject) => { 45 | if (!storj) { 46 | return reject(new errors.BadRequestError('No Storj instance')); 47 | } 48 | 49 | const keypair = storj.generateKeyPair(); 50 | 51 | commit(SET_PRIVATE_KEY, keypair.getPrivateKey()); 52 | commit(SET_PUBLIC_KEY, keypair.getPublicKey()); 53 | 54 | return resolve(keypair); 55 | }); 56 | }, 57 | 58 | /** 59 | * Registers public key with Storj network 60 | */ 61 | registerKey ({ commit, state }, data) { 62 | return new Promise((resolve, reject) => { 63 | if (!data.storj) { 64 | return reject(new errors.BadRequestError('No Storj instance')); 65 | } 66 | 67 | return data.storj.registerKey(data.publicKey, function (err) { 68 | if (err) { 69 | return reject(new errors.InternalError(err)); 70 | } 71 | return resolve(); 72 | }); 73 | }); 74 | }, 75 | 76 | /** 77 | * Unregister public key with Storj network and clear private key from 78 | * Vuex state 79 | */ 80 | unregisterKey ({ commit, dispatch }, storj) { 81 | return new Promise((resolve, reject) => { 82 | const privateKey = lStorage.retrieve('privateKey'); 83 | const publicKey = lStorage.retrieve('publicKey'); 84 | 85 | if (!privateKey || !publicKey) { 86 | return resolve(); 87 | } 88 | 89 | storj.removeKey(publicKey, function (err) { 90 | if (err) { 91 | if (err.toString() === 'Error: Public key was not found') { 92 | return resolve('Private key not found'); 93 | } 94 | return reject(new errors.InternalError(err.message)); 95 | } 96 | commit(CLEAR_KEYS); 97 | return resolve('Private key removed'); 98 | }); 99 | }); 100 | } 101 | }; 102 | 103 | export default { 104 | state, 105 | mutations, 106 | actions 107 | }; 108 | -------------------------------------------------------------------------------- /src/store/modules/marketing.js: -------------------------------------------------------------------------------- 1 | import { 2 | SET_MARKETING, 3 | CLEAR_MARKETING 4 | } from '../mutation-types'; 5 | import Promise from 'bluebird'; 6 | import billingClient from '@/api/billing-client'; 7 | import { lStorage } from '@/utils'; 8 | 9 | const state = { 10 | id: '', 11 | user: '', 12 | referralLink: '' 13 | }; 14 | 15 | const mutations = { 16 | [SET_MARKETING] (state, marketing) { 17 | state.id = marketing._id; 18 | state.user = marketing.user; 19 | state.referralLink = 'https://app.storj.io/signup?referralLink=' + marketing.referralLink; 20 | }, 21 | 22 | [CLEAR_MARKETING] (state) { 23 | state.id = ''; 24 | state.user = ''; 25 | state.referralLink = ''; 26 | } 27 | }; 28 | 29 | const actions = { 30 | getMarketing ({ commit }) { 31 | return new Promise((resolve, reject) => { 32 | const user = lStorage.retrieve('email'); 33 | billingClient.request('GET', '/marketing', { user }) 34 | .then((res) => { 35 | commit(SET_MARKETING, res.data); 36 | return resolve(); 37 | }) 38 | .catch((err) => reject(err)); 39 | }); 40 | }, 41 | 42 | sendEmails ({ commit, dispatch, state }, emails, marketing) { 43 | return new Promise((resolve, reject) => { 44 | billingClient 45 | .request('POST', '/referrals/sendReferralEmail', { 46 | marketing: state, 47 | emails 48 | }) 49 | .then((res) => resolve(res)) 50 | .catch((err) => reject(err)); 51 | }); 52 | } 53 | }; 54 | 55 | export default { 56 | state, 57 | mutations, 58 | actions 59 | }; 60 | -------------------------------------------------------------------------------- /src/store/modules/user.js: -------------------------------------------------------------------------------- 1 | import { 2 | SET_USER, 3 | CLEAR_USER 4 | } from '@/store/mutation-types'; 5 | import axios from 'axios'; 6 | import Promise from 'bluebird'; 7 | import config from '../../../config'; 8 | import { lStorage } from '@/utils'; 9 | import bridgeClient from '@/api/bridge-client'; 10 | 11 | const state = { 12 | email: lStorage.retrieve('email') 13 | }; 14 | 15 | const mutations = { 16 | [SET_USER] (state, email) { 17 | state.email = email; 18 | lStorage.save('email', email); 19 | }, 20 | 21 | [CLEAR_USER] (state) { 22 | state.email = ''; 23 | lStorage.remove('email'); 24 | } 25 | }; 26 | 27 | const actions = { 28 | /** 29 | * Creates a new Storj user 30 | */ 31 | createUser ({ commit, state }, credentials) { 32 | return new Promise((resolve, reject) => { 33 | axios 34 | .post(config.app.BRIDGE_URL + '/users', credentials) 35 | .then((result) => { 36 | commit(SET_USER, credentials.email); 37 | 38 | axios 39 | .post(config.app.BILLING_URL + '/credits/signups', { 40 | email: credentials.email, 41 | referralLink: credentials.referralLink 42 | }) 43 | .then((res) => resolve(res)) 44 | .catch((err) => reject(err)); 45 | }) 46 | .catch((err) => reject(err)); 47 | }); 48 | }, 49 | 50 | /** 51 | * "Delete" Storj account. Sets account to 'activated: false'. No way to 52 | * reactive. Part 1 of 2. 53 | */ 54 | // TODO: Works. Need to figure out what to do after sending confirmation email 55 | deleteAccount ({ commit, state }) { 56 | return new Promise((resolve, reject) => { 57 | const id = lStorage.retrieve('email'); 58 | bridgeClient.request('DELETE', `/users/${id}`) 59 | .then((res) => { 60 | console.log('res', res); 61 | }) 62 | .catch((err) => { 63 | console.log('err', err); 64 | }); 65 | }); 66 | } 67 | 68 | }; 69 | 70 | export default { 71 | state, 72 | mutations, 73 | actions 74 | }; 75 | -------------------------------------------------------------------------------- /src/store/mutation-types.js: -------------------------------------------------------------------------------- 1 | export const SET_USER = 'SET_USER'; 2 | export const CLEAR_USER = 'CLEAR_USER'; 3 | 4 | export const SET_AUTHENTICATION = 'SET_AUTHENTICATION'; 5 | 6 | export const SET_PRIVATE_KEY = 'SET_PRIVATE_KEY'; 7 | export const SET_PUBLIC_KEY = 'SET_PUBLIC_KEY'; 8 | export const CLEAR_KEYS = 'CLEAR_KEYS'; 9 | 10 | export const CREATE_KEY_PAIR = 'CREATE_KEY_PAIR'; 11 | 12 | export const SET_STORJ_INSTANCE = 'SET_STORJ_INSTANCE'; 13 | export const CLEAR_STORJ_INSTANCE = 'CLEAR_STORJ_INSTANCE'; 14 | 15 | export const SET_BUCKETS = 'SET_BUCKETS'; 16 | export const ADD_BUCKET = 'ADD_BUCKET'; 17 | export const SET_CURRENT_BUCKET_META = 'SET_CURRENT_BUCKET_META'; 18 | export const SET_CURRENT_BUCKET_FILES = 'SET_CURRENT_BUCKET_FILES'; 19 | export const CLEAR_BUCKET_STATE = 'CLEAR_BUCKET_STATE'; 20 | 21 | export const SET_CREDITS = 'SET_CREDITS'; 22 | export const SET_DEBITS = 'SET_DEBITS'; 23 | export const SET_DEFAULT_PAYMENT_METHOD = 'SET_DEFAULT_PAYMENT_METHOD'; 24 | export const CLEAR_DEFAULT_PAYMENT_METHOD = 'CLEAR_DEFAULT_PAYMENT_METHOD'; 25 | export const SET_BILLING_DATE = 'SET_BILLING_DATE'; 26 | export const SET_DEFAULT_PP_ID = 'SET_DEFAULT_PP_ID'; 27 | export const MARK_RETRIEVED = 'MARK_RETRIEVED'; 28 | export const SET_NEXT_BILLING_PERIOD = 'SET_NEXT_BILLING_PERIOD'; 29 | export const CLEAR_BILLING = 'CLEAR_BILLING'; 30 | 31 | export const SET_WALLETS = 'SET_WALLETS'; 32 | 33 | export const SET_STRIPE_TOKEN = 'SET_STRIPE_TOKEN'; 34 | export const CLEAR_STRIPE_TOKEN = 'CLEAR_STRIPE_TOKEN'; 35 | 36 | export const SET_MARKETING = 'SET_MARKETING'; 37 | export const CLEAR_MARKETING = 'CLEAR_MARKETING'; 38 | -------------------------------------------------------------------------------- /src/theme/bootstrap.config.js: -------------------------------------------------------------------------------- 1 | // TODO-Note: I think this can actually be taken out. Using bootstrap-vue does all this stuff 2 | 3 | /** 4 | * Bootstrap configuration for bootstrap-sass-loader 5 | * 6 | * Scripts are disabled to not load jQuery. 7 | * 8 | * In order to keep the bundle size low in production 9 | * disable components you don't use. 10 | * 11 | */ 12 | 13 | module.exports = { 14 | preBootstrapCustomizations: './src/theme/variables.scss', 15 | mainSass: './src/theme/bootstrap.overrides.scss', 16 | verbose: false, 17 | debug: false, 18 | scripts: { 19 | transition: false, 20 | alert: false, 21 | button: false, 22 | carousel: false, 23 | collapse: false, 24 | dropdown: false, 25 | modal: false, 26 | tooltip: false, 27 | popover: false, 28 | scrollspy: false, 29 | tab: false, 30 | affix: false 31 | }, 32 | styles: { 33 | mixins: true, 34 | normalize: true, 35 | print: true, 36 | glyphicons: true, 37 | scaffolding: true, 38 | type: true, 39 | code: true, 40 | grid: true, 41 | tables: true, 42 | forms: true, 43 | buttons: true, 44 | 'component-animations': true, 45 | dropdowns: true, 46 | 'button-groups': true, 47 | 'input-groups': true, 48 | navs: true, 49 | navbar: true, 50 | breadcrumbs: true, 51 | pagination: true, 52 | pager: true, 53 | labels: true, 54 | badges: true, 55 | jumbotron: true, 56 | thumbnails: true, 57 | alerts: true, 58 | 'progress-bars': true, 59 | media: true, 60 | 'list-group': true, 61 | panels: true, 62 | wells: true, 63 | 'responsive-embed': true, 64 | close: true, 65 | modals: true, 66 | tooltip: true, 67 | popovers: true, 68 | carousel: true, 69 | utilities: true, 70 | 'responsive-utilities': true 71 | } 72 | }; 73 | -------------------------------------------------------------------------------- /src/theme/bootstrap.config.prod.js: -------------------------------------------------------------------------------- 1 | const bootstrapConfig = require('./bootstrap.config.js'); 2 | const ExtractTextPlugin = require('extract-text-webpack-plugin'); 3 | bootstrapConfig.styleLoader = ExtractTextPlugin.extract('style-loader', 'css-loader!sass-loader'); 4 | module.exports = bootstrapConfig; 5 | 6 | -------------------------------------------------------------------------------- /src/theme/bootstrap.overrides.scss: -------------------------------------------------------------------------------- 1 | /* Bootstrap Style Overrides 2 | * 3 | */ 4 | 5 | @import 'variables'; 6 | /* -------------------------------- 7 | 8 | Fonts 9 | 10 | -------------------------------- */ 11 | @font-face { 12 | font-family: 'Avenir Next LT Pro Regular'; 13 | font-style: normal; 14 | font-weight: normal; 15 | src: local('Avenir Next LT Pro Regular'), url('../../static/fonts/AvenirNextLTPro-Regular.woff') format('woff'); 16 | } 17 | @font-face { 18 | font-family: 'Avenir Next LT Pro Demi'; 19 | font-style: normal; 20 | font-weight: normal; 21 | src: local('Avenir Next LT Pro Demi'), url('../../static/fonts/AvenirNextLTPro-Demi.woff') format('woff'); 22 | } 23 | 24 | @font-face { 25 | font-family: 'Avenir Next LT Pro Bold'; 26 | font-style: normal; 27 | font-weight: normal; 28 | src: local('Avenir Next LT Pro Bold'), url('../../static/fonts/AvenirNextLTPro-Bold.woff') format('woff'); 29 | } 30 | 31 | h1, h2, h3, h4, h5, h6, a, p, span { 32 | -webkit-font-feature-settings: 'kern' 1; 33 | -moz-font-feature-settings: 'kern' 1; 34 | -ms-font-feature-settings: 'kern' 1; 35 | -o-font-feature-settings: 'kern' 1; 36 | font-feature-settings: 'kern' 1; 37 | text-rendering: optimizelegibility; 38 | font-kerning: normal; 39 | } 40 | 41 | h1, h2, h3, h4, h5, h6 { 42 | color: $gray; 43 | letter-spacing: -1px; 44 | } 45 | 46 | .glyphicon { 47 | color: $brand-primary; 48 | opacity: 0.9; 49 | } 50 | 51 | a { 52 | outline: none; 53 | } 54 | 55 | .btn { 56 | font-family: 'Avenir Next LT Pro Demi'; 57 | border-width: 2px; 58 | -webkit-transition: all 0.15s ease-in-out; 59 | -moz-transition: all 0.15s ease-in-out; 60 | -ms-transition: all 0.15s ease-in-out; 61 | transition: all 0.15s ease-in-out; 62 | padding: 12px 36px 10px; 63 | } 64 | 65 | .btn:hover { 66 | cursor: pointer; 67 | } 68 | 69 | .btn-link:focus { 70 | outline:0; 71 | } 72 | 73 | .btn-xs { 74 | padding: 6px 12px 6px; 75 | } 76 | 77 | .btn-sm { 78 | padding: 10px 24px 8px; 79 | } 80 | 81 | .btn-lg { 82 | padding: 14px 60px 12px; 83 | } 84 | 85 | .navbar-btn { 86 | padding: 6px 36px; //navbar-btn top-bottom margins based on $input-height-base variable, set @ 6px 87 | } 88 | 89 | .navbar-default { 90 | border: 0; 91 | border-bottom: 2px solid $gray-lighter; 92 | border-radius: 0; 93 | background: #fff; 94 | } 95 | 96 | .navbar-default .nav>li>a { 97 | text-align: center; 98 | } 99 | 100 | .navbar-default .navbar-nav { 101 | margin-bottom: 0; 102 | margin-top: 0; 103 | } 104 | .navbar-default .navbar-nav>li>a { 105 | padding: 40px 16px; 106 | width: 100%; 107 | color: #8492a6; 108 | } 109 | .navbar-default .navbar-nav>li>a.active { 110 | font-family: 'Avenir Next LT Pro Demi'; 111 | } 112 | .navbar-default .navbar-nav>li>a:hover { 113 | color: #2683ff; 114 | } 115 | 116 | .navbar-default .nav>li>a:hover, 117 | .navbar-default .nav>li>a:focus, 118 | .navbar-default .navbar-nav>li>a.active { 119 | box-shadow: 0 2px $brand-primary; 120 | } 121 | 122 | .navbar-default .navbar-toggle { 123 | border: 2px solid $brand-primary; 124 | margin-top: 22px; 125 | margin-right: 22px; 126 | } 127 | 128 | .navbar-default .navbar-collapse, .navbar-default .navbar-form { 129 | border: 0; 130 | } 131 | 132 | .navbar-brand { 133 | margin: 25px; 134 | margin-right: 10px; 135 | height: auto; 136 | padding: 0; 137 | } 138 | 139 | 140 | .form-control { 141 | -webkit-box-shadow: none; 142 | box-shadow: none; 143 | } 144 | .form-control:focus { 145 | border-color: $brand-primary; 146 | } 147 | 148 | input, select { 149 | border-radius: 3px; 150 | font-size: 16px; 151 | -webkit-transition: all 0.15s ease-in-out; 152 | -moz-transition: all 0.15s ease-in-out; 153 | -ms-transition: all 0.15s ease-in-out; 154 | transition: all 0.15s ease-in-out; 155 | padding: 12px 18px 10px; 156 | color: $brand-primary; 157 | background: #fbfbfb; 158 | } 159 | 160 | .input-sm { 161 | font-size: 12px; 162 | padding: 10px 12px 8px; 163 | } 164 | 165 | .input-lg { 166 | font-size: 24px; 167 | padding: 16px 28px 12px; 168 | } 169 | 170 | input:focus, select:focus { 171 | border-color: $brand-primary; 172 | outline: 0; 173 | } 174 | 175 | .tooltip-inner { 176 | max-width: 350px; 177 | width: 350px; 178 | padding: 10px; 179 | } 180 | 181 | @media (min-width: 768px) and (max-width: 991px) { 182 | .navbar-default .navbar-brand { 183 | margin-right: 0; 184 | } 185 | } 186 | 187 | @media (max-width: 767px) { 188 | .navbar-default .navbar-right { 189 | text-align: center; 190 | padding-bottom: 1em; 191 | } 192 | .navbar-default .navbar-nav>li>a { 193 | padding: 16px; 194 | } 195 | .navbar-default .nav > li > a:hover, .navbar-default .nav > li > a:focus, .navbar-default .navbar-nav > li > a.active { 196 | box-shadow: none; 197 | background: #2683ff; 198 | color: #fff; 199 | } 200 | } 201 | 202 | @import 'theme'; 203 | -------------------------------------------------------------------------------- /src/theme/shame.scss: -------------------------------------------------------------------------------- 1 | /** The Island of Misfit Styles 2 | * The longer this file grows, the longer it will take to change styles. 3 | * Be kind and attempt to move these to components and themes. 4 | */ 5 | 6 | @import 'variables'; 7 | 8 | html { 9 | -webkit-font-smoothing: antialiased; 10 | -moz-osx-font-smoothing: grayscale; 11 | } 12 | 13 | label { 14 | margin-bottom: 0.8em; 15 | } 16 | 17 | .content { 18 | border: 1px solid #eee; 19 | background: #fff; 20 | border-radius: 5px; 21 | padding: 2em; 22 | margin-bottom: 2em; 23 | } 24 | 25 | .table-responsive.content { 26 | padding: 0; 27 | } 28 | 29 | .btn-action { 30 | margin-top: 8px; 31 | padding: 12px 36px 10px; 32 | } 33 | 34 | .btn-red { 35 | border-color: #fa6e50 36 | } 37 | 38 | .btn-block { 39 | font-size: 16px; 40 | margin: 0.5em auto; 41 | padding: 0.9em 0 0.8em; 42 | } 43 | 44 | input.parent-code { 45 | margin: 1.2em auto; 46 | line-height: 1.8em; 47 | } 48 | 49 | .title { 50 | margin-top: 0.5em; 51 | margin-bottom: 0.75em; 52 | } 53 | 54 | .loader { 55 | position: relative; 56 | display: block; 57 | width:50px; 58 | height:50px; 59 | margin: auto; 60 | } 61 | 62 | .files-container { 63 | padding: 0; 64 | } 65 | .files-container .form-group { 66 | margin-bottom: 0; 67 | } 68 | 69 | .btn-menu { 70 | margin-top: 25px; 71 | padding: 12px 32px 10px; 72 | } 73 | .btn-action { 74 | margin-top: 8px; 75 | padding: 12px 36px 10px; 76 | } 77 | .btn-link:focus, .btn-link:active { 78 | outline:0 !important; 79 | } 80 | 81 | // TODO Connect these variables to the main style sheet 82 | 83 | $brand-warning: #f0ad4e; 84 | $brand-danger: #d9534f; 85 | $brand-success: #91D127; 86 | 87 | .hidden { 88 | display: none !important; 89 | } 90 | .has-error { 91 | color: $brand-danger; 92 | } 93 | .has-success { 94 | border-color: $brand-success; 95 | } 96 | 97 | .alert-warning { 98 | color: darken($brand-warning, 40%); 99 | background-color: $brand-warning; 100 | } 101 | 102 | .blue { color: #2683ff; } 103 | .spacer5 { height: 5px; width: 100%; font-size: 0; margin: 0; padding: 0; border: 0; display: block; } 104 | .spacer10 { height: 10px; width: 100%; font-size: 0; margin: 0; padding: 0; border: 0; display: block; } 105 | .spacer15 { height: 15px; width: 100%; font-size: 0; margin: 0; padding: 0; border: 0; display: block; } 106 | .spacer20 { height: 20px; width: 100%; font-size: 0; margin: 0; padding: 0; border: 0; display: block; } 107 | .spacer25 { height: 25px; width: 100%; font-size: 0; margin: 0; padding: 0; border: 0; display: block; } 108 | .spacer30 { height: 30px; width: 100%; font-size: 0; margin: 0; padding: 0; border: 0; display: block; } 109 | .spacer35 { height: 35px; width: 100%; font-size: 0; margin: 0; padding: 0; border: 0; display: block; } 110 | .spacer40 { height: 40px; width: 100%; font-size: 0; margin: 0; padding: 0; border: 0; display: block; } 111 | .spacer45 { height: 45px; width: 100%; font-size: 0; margin: 0; padding: 0; border: 0; display: block; } 112 | .spacer50 { height: 50px; width: 100%; font-size: 0; margin: 0; padding: 0; border: 0; display: block; } 113 | .spacer100 { height: 100px; width: 100%; font-size: 0; margin: 0; padding: 0; border: 0; display: block; } 114 | .spacer200 { height: 200px; width: 100%; font-size: 0; margin: 0; padding: 0; border: 0; display: block; } 115 | 116 | .mb0 { margin-bottom: 0 !important; } 117 | .mt0 { margin-top: 0 !important; } 118 | .ml0 { margin-left: 0 !important; } 119 | .mr0 { margin-right: 0 !important; } 120 | /* -------------------------------- 121 | 122 | Media Queries 123 | 124 | -------------------------------- */ 125 | 126 | @media (min-width: 768px) and (max-width: 991px) { 127 | .btn-menu { 128 | padding-left: 15px; 129 | padding-right: 15px; 130 | } 131 | } 132 | 133 | @media (max-width: 767px) { 134 | .btn-menu { 135 | width: 100%; 136 | margin: 0.5em 0; 137 | } 138 | } 139 | 140 | @media (max-width: 480px) { 141 | .btn-action { 142 | padding-left: 10px; 143 | padding-right: 10px; 144 | } 145 | .btn-block { 146 | font-size: 16px; 147 | } 148 | .menu { 149 | padding: 30px 0 20px; 150 | } 151 | } 152 | -------------------------------------------------------------------------------- /src/theme/styles.scss: -------------------------------------------------------------------------------- 1 | @import 'bootstrap.overrides'; 2 | @import 'shame'; 3 | -------------------------------------------------------------------------------- /src/theme/utils.scss: -------------------------------------------------------------------------------- 1 | .display-none { 2 | content: ''; 3 | display: none; 4 | } 5 | -------------------------------------------------------------------------------- /src/utils/validation.js: -------------------------------------------------------------------------------- 1 | const isEmpty = value => value === undefined || value === null || value === ''; 2 | const join = (rules) => (value, data) => rules.map(rule => rule(value, data)).filter(error => !!error)[0]; 3 | 4 | export function email (value) { 5 | if (isEmpty(value) || !isValidEmail(value)) { 6 | return 'Invalid email address'; 7 | } 8 | } 9 | 10 | export function isValidEmail (value) { 11 | const regex = /^(([^<>()[\]\\.,;:\s@"]+(\.[^<>()[\]\\.,;:\s@"]+)*)|(".+"))@(([0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3})|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/; // jshint ignore:line 12 | return regex.test(value); 13 | } 14 | 15 | export function required (value) { 16 | if (isEmpty(value)) { 17 | return 'Required'; 18 | } 19 | } 20 | 21 | export function minLength (min) { 22 | return value => { 23 | if (!isEmpty(value) && value.length < min) { 24 | return `Must be at least ${min} characters`; 25 | } 26 | }; 27 | } 28 | 29 | export function maxLength (max) { 30 | return value => { 31 | if (!isEmpty(value) && value.length > max) { 32 | return `Must be no more than ${max} characters`; 33 | } 34 | }; 35 | } 36 | 37 | export function integer (value) { 38 | if (!Number.isInteger(Number(value))) { 39 | return 'Must be an integer'; 40 | } 41 | } 42 | 43 | export function oneOf (enumeration) { 44 | return value => { 45 | if (!~enumeration.indexOf(value)) { 46 | return `Must be one of: ${enumeration.join(', ')}`; 47 | } 48 | }; 49 | } 50 | 51 | export function match (field) { 52 | return (value, data) => { 53 | if (data) { 54 | if (value !== data[field]) { 55 | return 'Do not match'; 56 | } 57 | } 58 | }; 59 | } 60 | 61 | export function createValidator (rules) { 62 | return (data = {}) => { 63 | const errors = {}; 64 | Object.keys(rules).forEach((key) => { 65 | const rule = join([].concat(rules[key])); // concat enables both functions and arrays of functions 66 | const error = rule(data[key], data); 67 | if (error) { 68 | errors[key] = error; 69 | } 70 | }); 71 | return errors; 72 | }; 73 | } 74 | 75 | /** 76 | * Validates credit card numbers 77 | * @param {String} ccNumber.error 78 | * @param {String} ccNumber.value 79 | * @returns {Object} 80 | */ 81 | export function validateCCNumber (ccNumber) { 82 | ccNumber.error = ''; 83 | 84 | // Validation regexes 85 | const visa = /^4[0-9]{12}(?:[0-9]{3})?$/.test(ccNumber.value); 86 | const mastercard = /^(?:5[1-5][0-9]{2}|222[1-9]|22[3-9][0-9]|2[3-6][0-9]{2}|27[01][0-9]|2720)[0-9]{12}$/.test(ccNumber.value); 87 | const amex = /^3[47][0-9]{13}$/.test(ccNumber.value); 88 | const discover = /^6(?:011|5[0-9]{2})[0-9]{12}$/.test(ccNumber.value); 89 | const jcb = /^(?:2131|1800|35\d{3})\d{11}$/.test(ccNumber.value); 90 | const dinersclub = /^3(?:0[0-5]|[68][0-9])[0-9]{11}$/.test(ccNumber.value); 91 | 92 | if (!ccNumber.value) { 93 | return ccNumber; 94 | } 95 | 96 | if (!visa && !mastercard && !amex && !discover && !jcb && !dinersclub) { 97 | ccNumber.error = 'Enter a valid credit card number'; 98 | } 99 | 100 | return ccNumber; 101 | } 102 | 103 | /** 104 | * Validates CVC 105 | * @param {String} cvc.error 106 | * @param {String} cvc.value 107 | * @returns {Object} 108 | */ 109 | export function validateCVC (cvc) { 110 | const cvcIsValid = /^([0-9]{3,4})$/.test(cvc.value); 111 | cvc.error = ''; 112 | 113 | if (!cvc.value) { 114 | return cvc; 115 | } 116 | 117 | if (!cvcIsValid) { 118 | cvc.error = 'Please enter a valid CVC'; 119 | } 120 | 121 | return cvc; 122 | } 123 | 124 | /** 125 | * Validates CC Expiration in MM/YY format 126 | * @param {String} ccExp.error 127 | * @param {String} ccExp.value 128 | * @returns {Object} 129 | */ 130 | export function validateCCExp (ccExp) { 131 | const ccExpIsValidYear = 132 | /^(?:0?[1-9]|1[0-2])*\/*[1-9][0-9]$/.test(ccExp.value); 133 | ccExp.error = ''; 134 | 135 | if (!ccExp.value) { 136 | return ccExp; 137 | } 138 | 139 | if (!ccExpIsValidYear) { 140 | ccExp.error = 'Please enter a valid expiration date (MM/YY)'; 141 | } 142 | 143 | return ccExp; 144 | } 145 | 146 | /** 147 | * Validates if CC form can be submitted 148 | * @params {Object} fields 149 | * @returns {Boolean} 150 | */ 151 | export function validateCCForm (fields) { 152 | const { ccNumber, cvc, ccExp, zip } = fields; 153 | 154 | if (cvc.error || ccExp.error || ccNumber.error || !cvc.value || 155 | !ccExp.value || !ccNumber.value || zip.value.length <= 2) { 156 | return false; 157 | } 158 | 159 | return true; 160 | } 161 | -------------------------------------------------------------------------------- /src/vendors/analytics.js: -------------------------------------------------------------------------------- 1 | // /* eslint-disable */ 2 | // !function(){var analytics=window.analytics=window.analytics||[];if(!analytics.initialize)if(analytics.invoked)window.console&&console.error&&console.error("Segment snippet included twice.");else{analytics.invoked=!0;analytics.methods=["trackSubmit","trackClick","trackLink","trackForm","pageview","identify","reset","group","track","ready","alias","debug","page","once","off","on"];analytics.factory=function(t){return function(){var e=Array.prototype.slice.call(arguments);e.unshift(t);analytics.push(e);return analytics}};for(var t=0;t { 11 | const { ccNumber, ccExp, cvc, zip } = opts; 12 | 13 | Stripe.card.createToken({ 14 | number: ccNumber.value, 15 | cvc: cvc.value, 16 | exp: ccExp.value, 17 | address_zip: zip.value 18 | }, (status, response) => { 19 | if (response.error) { 20 | return reject(new errors.InternalError( 21 | `Processing error: ${response.error.message}` 22 | )); 23 | } 24 | 25 | const token = response.id; 26 | return resolve(token); 27 | }); 28 | }); 29 | }; 30 | -------------------------------------------------------------------------------- /src/views/Billing/Balance-Panel.vue: -------------------------------------------------------------------------------- 1 | 16 | 17 | 43 | 44 | 46 | -------------------------------------------------------------------------------- /src/views/Billing/Payment-Panel.vue: -------------------------------------------------------------------------------- 1 | 51 | 52 | 93 | 94 | 110 | -------------------------------------------------------------------------------- /src/views/Billing/Transaction-List.vue: -------------------------------------------------------------------------------- 1 | 58 | 59 | 150 | 151 | 171 | -------------------------------------------------------------------------------- /src/views/Billing/Usage-Panel.vue: -------------------------------------------------------------------------------- 1 | 35 | 36 | 74 | 75 | 77 | -------------------------------------------------------------------------------- /src/views/Billing/index.vue: -------------------------------------------------------------------------------- 1 | 31 | 32 | 96 | 97 | 122 | -------------------------------------------------------------------------------- /src/views/Buckets/Bucket-Files/Bucket-File-List.vue: -------------------------------------------------------------------------------- 1 | 39 | 40 | 47 | 48 | 50 | -------------------------------------------------------------------------------- /src/views/Buckets/Bucket-Files/index.vue: -------------------------------------------------------------------------------- 1 | 65 | 66 | 126 | 127 | 140 | -------------------------------------------------------------------------------- /src/views/Buckets/Bucket-List/Bucket-List-Items.vue: -------------------------------------------------------------------------------- 1 | 32 | 33 | 48 | 49 | 98 | -------------------------------------------------------------------------------- /src/views/Buckets/Bucket-List/index.vue: -------------------------------------------------------------------------------- 1 | 29 | 30 | 64 | 65 | 70 | -------------------------------------------------------------------------------- /src/views/Buckets/Bucket-Settings/Public-Key-List.vue: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/storj-archived/bridge-gui-vue/337a410f73fd46e132bf11ab0a7b201908d78ca2/src/views/Buckets/Bucket-Settings/Public-Key-List.vue -------------------------------------------------------------------------------- /src/views/Buckets/Bucket-Settings/index.vue: -------------------------------------------------------------------------------- 1 | 70 | 71 | 92 | 93 | 95 | -------------------------------------------------------------------------------- /src/views/Buckets/Create-Bucket/index.vue: -------------------------------------------------------------------------------- 1 | 61 | 62 | 125 | 126 | 131 | -------------------------------------------------------------------------------- /src/views/Buckets/index.vue: -------------------------------------------------------------------------------- 1 | 13 | 14 | 24 | 25 | 28 | -------------------------------------------------------------------------------- /src/views/Dashboard/index.vue: -------------------------------------------------------------------------------- 1 | 45 | 46 | 75 | 76 | 132 | 134 | -------------------------------------------------------------------------------- /src/views/Not-Found/index.vue: -------------------------------------------------------------------------------- 1 | 7 | 8 | 13 | 14 | 19 | -------------------------------------------------------------------------------- /src/views/Password-Reset/index.vue: -------------------------------------------------------------------------------- 1 | 62 | 63 | 105 | 106 | 108 | -------------------------------------------------------------------------------- /src/views/Password-Reset/password-set.vue: -------------------------------------------------------------------------------- 1 | 66 | 132 | 138 | 139 | -------------------------------------------------------------------------------- /src/views/Referrals/Referral-Email.vue: -------------------------------------------------------------------------------- 1 | 58 | 59 | 120 | 121 | 157 | -------------------------------------------------------------------------------- /src/views/Referrals/Referral-Info.vue: -------------------------------------------------------------------------------- 1 | 16 | 17 | 22 | 23 | 25 | -------------------------------------------------------------------------------- /src/views/Referrals/Referral-Link.vue: -------------------------------------------------------------------------------- 1 | 32 | 33 | 60 | 61 | 78 | -------------------------------------------------------------------------------- /src/views/Referrals/index.vue: -------------------------------------------------------------------------------- 1 | 19 | 20 | 59 | 60 | 62 | -------------------------------------------------------------------------------- /src/views/Settings/index.vue: -------------------------------------------------------------------------------- 1 | 38 | 39 | 44 | 45 | 48 | -------------------------------------------------------------------------------- /src/views/Support/index.vue: -------------------------------------------------------------------------------- 1 | 6 | 7 | 12 | 13 | 15 | -------------------------------------------------------------------------------- /static/crossdomain.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 15 | 16 | -------------------------------------------------------------------------------- /static/fonts/AvenirNextLTPro-Bold.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/storj-archived/bridge-gui-vue/337a410f73fd46e132bf11ab0a7b201908d78ca2/static/fonts/AvenirNextLTPro-Bold.woff -------------------------------------------------------------------------------- /static/fonts/AvenirNextLTPro-Demi.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/storj-archived/bridge-gui-vue/337a410f73fd46e132bf11ab0a7b201908d78ca2/static/fonts/AvenirNextLTPro-Demi.woff -------------------------------------------------------------------------------- /static/fonts/AvenirNextLTPro-Regular.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/storj-archived/bridge-gui-vue/337a410f73fd46e132bf11ab0a7b201908d78ca2/static/fonts/AvenirNextLTPro-Regular.woff -------------------------------------------------------------------------------- /static/fonts/glyphicons-halflings-regular.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/storj-archived/bridge-gui-vue/337a410f73fd46e132bf11ab0a7b201908d78ca2/static/fonts/glyphicons-halflings-regular.eot -------------------------------------------------------------------------------- /static/fonts/glyphicons-halflings-regular.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/storj-archived/bridge-gui-vue/337a410f73fd46e132bf11ab0a7b201908d78ca2/static/fonts/glyphicons-halflings-regular.ttf -------------------------------------------------------------------------------- /static/fonts/glyphicons-halflings-regular.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/storj-archived/bridge-gui-vue/337a410f73fd46e132bf11ab0a7b201908d78ca2/static/fonts/glyphicons-halflings-regular.woff -------------------------------------------------------------------------------- /static/fonts/glyphicons-halflings-regular.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/storj-archived/bridge-gui-vue/337a410f73fd46e132bf11ab0a7b201908d78ca2/static/fonts/glyphicons-halflings-regular.woff2 -------------------------------------------------------------------------------- /static/img/bg.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/storj-archived/bridge-gui-vue/337a410f73fd46e132bf11ab0a7b201908d78ca2/static/img/bg.jpg -------------------------------------------------------------------------------- /static/img/favicon/favicon-16x16.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/storj-archived/bridge-gui-vue/337a410f73fd46e132bf11ab0a7b201908d78ca2/static/img/favicon/favicon-16x16.png -------------------------------------------------------------------------------- /static/img/favicon/favicon-32x32.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/storj-archived/bridge-gui-vue/337a410f73fd46e132bf11ab0a7b201908d78ca2/static/img/favicon/favicon-32x32.png -------------------------------------------------------------------------------- /static/img/favicon/favicon-96x96.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/storj-archived/bridge-gui-vue/337a410f73fd46e132bf11ab0a7b201908d78ca2/static/img/favicon/favicon-96x96.png -------------------------------------------------------------------------------- /static/img/favicon/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/storj-archived/bridge-gui-vue/337a410f73fd46e132bf11ab0a7b201908d78ca2/static/img/favicon/favicon.ico -------------------------------------------------------------------------------- /static/img/icon-api.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Slice 1 5 | Created with Sketch. 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | -------------------------------------------------------------------------------- /static/img/icon-bandwidth.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | icon-bandwidth 5 | Created with Sketch. 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | -------------------------------------------------------------------------------- /static/img/icon-bitcoin.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /static/img/icon-bucket.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Stroke 469 + Stroke 2476 + Stroke 2477 5 | Created with Sketch. 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /static/img/icon-capacity.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | icon-storage2 5 | Created with Sketch. 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | -------------------------------------------------------------------------------- /static/img/icon-cli.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | icon-cli 5 | Created with Sketch. 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | -------------------------------------------------------------------------------- /static/img/icon-cost.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | icon-cost 5 | Created with Sketch. 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | -------------------------------------------------------------------------------- /static/img/icon-dropdown.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Triangle 1 5 | Created with Sketch. 6 | 7 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /static/img/icon-fast.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | icon-fast 5 | Created with Sketch. 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | -------------------------------------------------------------------------------- /static/img/icon-logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/storj-archived/bridge-gui-vue/337a410f73fd46e132bf11ab0a7b201908d78ca2/static/img/icon-logo.png -------------------------------------------------------------------------------- /static/img/icon-safe.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | icon-safe 5 | Created with Sketch. 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | -------------------------------------------------------------------------------- /static/img/icon-storage.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | icon-storage 5 | Created with Sketch. 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | -------------------------------------------------------------------------------- /static/img/icon-uptime.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Stroke 517 + Stroke 518 + Stroke 519 5 | Created with Sketch. 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /static/img/icon-users.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | icon-users 5 | Created with Sketch. 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | -------------------------------------------------------------------------------- /static/img/icon-web.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | icon-web 5 | Created with Sketch. 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | -------------------------------------------------------------------------------- /static/img/logo-amazons3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/storj-archived/bridge-gui-vue/337a410f73fd46e132bf11ab0a7b201908d78ca2/static/img/logo-amazons3.png -------------------------------------------------------------------------------- /static/img/logo-azure.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/storj-archived/bridge-gui-vue/337a410f73fd46e132bf11ab0a7b201908d78ca2/static/img/logo-azure.png -------------------------------------------------------------------------------- /static/img/metadisk.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/storj-archived/bridge-gui-vue/337a410f73fd46e132bf11ab0a7b201908d78ca2/static/img/metadisk.png -------------------------------------------------------------------------------- /static/img/social-github.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Group 5 | Created with Sketch. 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /static/img/social-reddit.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Group 5 | Created with Sketch. 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | -------------------------------------------------------------------------------- /static/img/social-twitter.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Stroke 39 5 | Created with Sketch. 6 | 7 | 8 | 9 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /static/img/storj.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/storj-archived/bridge-gui-vue/337a410f73fd46e132bf11ab0a7b201908d78ca2/static/img/storj.png -------------------------------------------------------------------------------- /static/robots.txt: -------------------------------------------------------------------------------- 1 | # http://www.robotstxt.org 2 | User-agent: * 3 | Disallow: 4 | -------------------------------------------------------------------------------- /test/e2e/custom-assertions/elementCount.js: -------------------------------------------------------------------------------- 1 | // A custom Nightwatch assertion. 2 | // the name of the method is the filename. 3 | // can be used in tests like this: 4 | // 5 | // browser.assert.elementCount(selector, count) 6 | // 7 | // for how to write custom assertions see 8 | // http://nightwatchjs.org/guide#writing-custom-assertions 9 | exports.assertion = function (selector, count) { 10 | this.message = 'Testing if element <' + selector + '> has count: ' + count 11 | this.expected = count 12 | this.pass = function (val) { 13 | return val === this.expected 14 | } 15 | this.value = function (res) { 16 | return res.value 17 | } 18 | this.command = function (cb) { 19 | var self = this 20 | return this.api.execute(function (selector) { 21 | return document.querySelectorAll(selector).length 22 | }, [selector], function (res) { 23 | cb.call(self, res) 24 | }) 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /test/e2e/nightwatch.conf.js: -------------------------------------------------------------------------------- 1 | require('babel-register') 2 | var config = require('../../config') 3 | 4 | // http://nightwatchjs.org/guide#settings-file 5 | module.exports = { 6 | src_folders: ['test/e2e/specs'], 7 | output_folder: 'test/e2e/reports', 8 | custom_assertions_path: ['test/e2e/custom-assertions'], 9 | 10 | selenium: { 11 | start_process: true, 12 | server_path: require('selenium-server').path, 13 | host: '127.0.0.1', 14 | port: 4444, 15 | cli_args: { 16 | 'webdriver.chrome.driver': require('chromedriver').path 17 | } 18 | }, 19 | 20 | test_settings: { 21 | default: { 22 | selenium_port: 4444, 23 | selenium_host: 'localhost', 24 | silent: true, 25 | globals: { 26 | devServerURL: 'http://localhost:' + (process.env.PORT || config.dev.port) 27 | } 28 | }, 29 | 30 | chrome: { 31 | desiredCapabilities: { 32 | browserName: 'chrome', 33 | javascriptEnabled: true, 34 | acceptSslCerts: true 35 | } 36 | }, 37 | 38 | firefox: { 39 | desiredCapabilities: { 40 | browserName: 'firefox', 41 | javascriptEnabled: true, 42 | acceptSslCerts: true 43 | } 44 | } 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /test/e2e/runner.js: -------------------------------------------------------------------------------- 1 | // 1. start the dev server using production config 2 | process.env.NODE_ENV = 'testing' 3 | var server = require('../../build/dev-server.js') 4 | 5 | // 2. run the nightwatch test suite against it 6 | // to run in additional browsers: 7 | // 1. add an entry in test/e2e/nightwatch.conf.json under "test_settings" 8 | // 2. add it to the --env flag below 9 | // or override the environment flag, for example: `npm run e2e -- --env chrome,firefox` 10 | // For more information on Nightwatch's config file, see 11 | // http://nightwatchjs.org/guide#settings-file 12 | var opts = process.argv.slice(2) 13 | if (opts.indexOf('--config') === -1) { 14 | opts = opts.concat(['--config', 'test/e2e/nightwatch.conf.js']) 15 | } 16 | if (opts.indexOf('--env') === -1) { 17 | opts = opts.concat(['--env', 'chrome']) 18 | } 19 | 20 | var spawn = require('cross-spawn') 21 | var runner = spawn('./node_modules/.bin/nightwatch', opts, { stdio: 'inherit' }) 22 | 23 | runner.on('exit', function (code) { 24 | server.close() 25 | process.exit(code) 26 | }) 27 | 28 | runner.on('error', function (err) { 29 | server.close() 30 | throw err 31 | }) 32 | -------------------------------------------------------------------------------- /test/e2e/specs/test.js: -------------------------------------------------------------------------------- 1 | // For authoring Nightwatch tests, see 2 | // http://nightwatchjs.org/guide#usage 3 | 4 | module.exports = { 5 | 'default e2e tests': function (browser) { 6 | // automatically uses dev Server port from /config.index.js 7 | // default: http://localhost:8080 8 | // see nightwatch.conf.js 9 | const devServer = browser.globals.devServerURL 10 | 11 | browser 12 | .url(devServer) 13 | .waitForElementVisible('#app', 5000) 14 | .assert.elementPresent('.hello') 15 | .assert.containsText('h1', 'Welcome to Your Vue.js App') 16 | .assert.elementCount('img', 1) 17 | .end() 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /test/unit/.eslintrc: -------------------------------------------------------------------------------- 1 | { 2 | "env": { 3 | "mocha": true 4 | }, 5 | "globals": { 6 | "expect": true, 7 | "sinon": true 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /test/unit/index.js: -------------------------------------------------------------------------------- 1 | import Vue from 'vue' 2 | Vue.config.productionTip = false 3 | 4 | // Polyfill fn.bind() for PhantomJS 5 | /* eslint-disable no-extend-native */ 6 | Function.prototype.bind = require('function-bind') 7 | 8 | // require all test files (files that ends with .spec.js) 9 | const testsContext = require.context('./specs', true, /\.spec$/) 10 | testsContext.keys().forEach(testsContext) 11 | 12 | // require all src files except main.js for coverage. 13 | // you can also change this to match only the subset of files that 14 | // you want coverage for. 15 | const srcContext = require.context('../../src', true, /^\.\/(?!main(\.js)?$)/) 16 | srcContext.keys().forEach(srcContext) 17 | -------------------------------------------------------------------------------- /test/unit/karma.conf.js: -------------------------------------------------------------------------------- 1 | // This is a karma config file. For more details see 2 | // http://karma-runner.github.io/0.13/config/configuration-file.html 3 | // we are also using it with karma-webpack 4 | // https://github.com/webpack/karma-webpack 5 | 6 | var webpackConfig = require('../../build/webpack.test.conf') 7 | 8 | module.exports = function (config) { 9 | config.set({ 10 | // to run in additional browsers: 11 | // 1. install corresponding karma launcher 12 | // http://karma-runner.github.io/0.13/config/browsers.html 13 | // 2. add it to the `browsers` array below. 14 | browsers: ['PhantomJS'], 15 | frameworks: ['mocha', 'sinon-chai'], 16 | reporters: ['spec', 'coverage'], 17 | files: ['./index.js'], 18 | preprocessors: { 19 | './index.js': ['webpack', 'sourcemap'] 20 | }, 21 | webpack: webpackConfig, 22 | webpackMiddleware: { 23 | noInfo: true 24 | }, 25 | coverageReporter: { 26 | dir: './coverage', 27 | reporters: [ 28 | { type: 'lcov', subdir: '.' }, 29 | { type: 'text-summary' } 30 | ] 31 | } 32 | }) 33 | } 34 | -------------------------------------------------------------------------------- /test/unit/specs/Hello.spec.js: -------------------------------------------------------------------------------- 1 | import Vue from 'vue' 2 | import Hello from '@/components/Hello' 3 | 4 | describe('Hello.vue', () => { 5 | it('should render correct contents', () => { 6 | const Constructor = Vue.extend(Hello) 7 | const vm = new Constructor().$mount() 8 | expect(vm.$el.querySelector('.hello h1').textContent) 9 | .to.equal('Welcome to Your Vue.js App') 10 | }) 11 | }) 12 | -------------------------------------------------------------------------------- /vendors/analytics.js: -------------------------------------------------------------------------------- 1 | /* esling-disable */ 2 | !function(){var analytics=window.analytics=window.analytics||[];if(!analytics.initialize)if(analytics.invoked)window.console&&console.error&&console.error("Segment snippet included twice.");else{analytics.invoked=!0;analytics.methods=["trackSubmit","trackClick","trackLink","trackForm","pageview","identify","reset","group","track","ready","alias","debug","page","once","off","on"];analytics.factory=function(t){return function(){var e=Array.prototype.slice.call(arguments);e.unshift(t);analytics.push(e);return analytics}};for(var t=0;t