Merge pull request #252 from colkito/feature/password-web-encryption
Feature/password web encryption // tons of good job!!
This commit is contained in:
commit
493f5c3427
14 changed files with 217 additions and 96 deletions
|
|
@ -42,7 +42,9 @@ var config = {
|
|||
port: 3001
|
||||
},
|
||||
verbose: 1,
|
||||
themes: ['default']
|
||||
themes: ['default'],
|
||||
iterations: 1000,
|
||||
storageSalt: 'mjuBtGybi/4=', // choose your own salt (base64)
|
||||
};
|
||||
|
||||
var log = function () {
|
||||
|
|
|
|||
4
copay.js
4
copay.js
|
|
@ -3,6 +3,8 @@
|
|||
module.exports.PublicKeyRing = require('./js/models/core/PublicKeyRing');
|
||||
module.exports.TxProposals = require('./js/models/core/TxProposals');
|
||||
module.exports.PrivateKey = require('./js/models/core/PrivateKey');
|
||||
module.exports.Passphrase = require('./js/models/core/Passphrase');
|
||||
|
||||
|
||||
// components
|
||||
var WebRTC = module.exports.WebRTC = require('./js/models/network/WebRTC');
|
||||
|
|
@ -13,7 +15,7 @@ var StorageLocalEncrypted = module.exports.StorageLocalEncrypted = require('./js
|
|||
var WalletFactory = require('soop').load('./js/models/core/WalletFactory',{
|
||||
Network: WebRTC,
|
||||
Blockchain: Insight,
|
||||
Storage: StorageLocalPlain,
|
||||
Storage: StorageLocalEncrypted,
|
||||
});
|
||||
module.exports.WalletFactory = WalletFactory;
|
||||
|
||||
|
|
|
|||
|
|
@ -356,15 +356,15 @@ hr { margin: 2.25rem 0;}
|
|||
.box-setup-copayers:after {
|
||||
border-color: rgba(255, 255, 255, 0);
|
||||
border-bottom-color: #ffffff;
|
||||
border-width: 30px;
|
||||
margin-left: -30px;
|
||||
border-width: 20px;
|
||||
margin-left: -20px;
|
||||
}
|
||||
|
||||
.box-setup-copayers:before {
|
||||
border-color: rgba(238, 238, 238, 0);
|
||||
border-bottom-color: #eee;
|
||||
border-width: 33px;
|
||||
margin-left: -33px;
|
||||
border-width: 23px;
|
||||
margin-left: -23px;
|
||||
}
|
||||
|
||||
.box-setup-copayers-fix {
|
||||
|
|
|
|||
87
index.html
87
index.html
|
|
@ -142,34 +142,31 @@
|
|||
Looking for peers...
|
||||
</div>
|
||||
<div ng-show="!loading">
|
||||
|
||||
<div class="row">
|
||||
<div class="large-6 columns">
|
||||
<div class="box-signin">
|
||||
<h3>Join a Wallet in Creation</h3>
|
||||
<input type="text" class="form-control" placeholder="Paste wallet secret here"
|
||||
ng-model="connectionId" required autofocus>
|
||||
<input type="text" class="form-control" placeholder="Your name (optional)"
|
||||
ng-model="nickname">
|
||||
<button class="button primary expand radius"
|
||||
ng-click="join(connectionId,nickname)" ng-disabled="loading" loading="Joining">Join</button>
|
||||
<h3>Join a Wallet in Creation</h3>
|
||||
<input type="text" class="form-control" placeholder="Paste wallet secret here" ng-model="connectionId" required autofocus>
|
||||
<input type="password" class="form-control" placeholder="Your wallet password" ng-model="joinPassword">
|
||||
<input type="text" class="form-control" placeholder="Your name (optional)" ng-model="nickname">
|
||||
<button class="button primary expand radius" ng-click="join()" ng-disabled="loading" loading="Joining">Join</button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="large-6 columns">
|
||||
<div class="box-signin">
|
||||
<div ng-show="wallets.length">
|
||||
<h3>Open Wallet</h3>
|
||||
<select class="form-control" ng-model="selectedWalletId"
|
||||
ng-options="w.id as w.show for w in wallets">
|
||||
</select>
|
||||
<button class="button secondary expand radius" type="button"
|
||||
ng-click="open(selectedWalletId)" ng-disabled="loading" loading="Opening">Open</button>
|
||||
</div>
|
||||
<div ng-show="!wallets.length">
|
||||
<h3>Create a new wallet</h3>
|
||||
<input type="text" class="form-control" ng-model="walletName" placeholder="Wallet name (optional)">
|
||||
<button class="button secondary expand radius" ng-click="create(walletName)" ng-disabled="loading" loading="Creating">Create</button>
|
||||
</div>
|
||||
<div ng-show="wallets.length">
|
||||
<h3>Open Wallet</h3>
|
||||
<select class="form-control" ng-model="selectedWalletId" ng-options="w.id as w.show for w in wallets">
|
||||
</select>
|
||||
<input type="password" class="form-control" placeholder="Your wallet password" ng-model="openPassword">
|
||||
<button class="button secondary expand radius" type="button" ng-click="open()" ng-disabled="loading" loading="Opening">Open</button>
|
||||
</div>
|
||||
<div ng-show="!wallets.length">
|
||||
<h3>Create a new wallet</h3>
|
||||
<input type="text" class="form-control" ng-model="walletName" placeholder="Wallet name (optional)">
|
||||
<input type="password" class="form-control" placeholder="Your wallet password" ng-model="createPassword">
|
||||
<button class="button secondary expand radius" ng-click="create()" ng-disabled="loading" loading="Creating">Create</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
|
@ -182,8 +179,6 @@
|
|||
<a ng-href="#import">Import from file</a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
</div> <!-- End !loading -->
|
||||
</div>
|
||||
</script>
|
||||
|
|
@ -191,7 +186,6 @@
|
|||
<script type="text/ng-template" id="import.html">
|
||||
<div ng-controller="ImportController">
|
||||
<h3>{{title}}</h3>
|
||||
|
||||
<div class="large-6 columns">
|
||||
<input type="file" class="form-control" placeholder="Select a backup file" ng-model="backupFile" autofocus="" ng-file-select>
|
||||
</div>
|
||||
|
|
@ -206,18 +200,16 @@
|
|||
<div ng-show="!loading">
|
||||
<div class="row">
|
||||
<div class="small-12 medium-8 medium-centered large-8 large-centered columns box-setup">
|
||||
<div class="large-6 columns line-dashed-v">
|
||||
<h6>Select total number of copayers</h6>
|
||||
<select ng-model="totalCopayers"
|
||||
ng-options="totalCopayers as totalCopayers for totalCopayers in TCValues">
|
||||
</select>
|
||||
</div>
|
||||
<div class="large-6 columns">
|
||||
<h6>Select required number of signatures</h6>
|
||||
<select ng-model="requiredCopayers"
|
||||
ng-options="requiredCopayers as requiredCopayers for requiredCopayers in RCValues">
|
||||
</select>
|
||||
</div>
|
||||
<div class="large-6 columns line-dashed-v">
|
||||
<h6>Select total number of copayers</h6>
|
||||
<select ng-model="totalCopayers" ng-options="totalCopayers as totalCopayers for totalCopayers in TCValues">
|
||||
</select>
|
||||
</div>
|
||||
<div class="large-6 columns">
|
||||
<h6>Select required number of signatures</h6>
|
||||
<select ng-model="requiredCopayers" ng-options="requiredCopayers as requiredCopayers for requiredCopayers in RCValues">
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
|
|
@ -228,23 +220,23 @@
|
|||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="row">
|
||||
<div class="small-12 medium-6 medium-centered large-6 large-centered columns m30v">
|
||||
<h6>Wallet name (optional)</h6>
|
||||
<input type="text" class="form-control" ng-model="walletName" placeholder="Enter wallet name">
|
||||
<h6>Wallet Password</h6>
|
||||
<input type="password" class="form-control" ng-model="walletPassword" required>
|
||||
</div>
|
||||
<div class="small-12 medium-6 medium-centered large-6 large-centered columns m30v">
|
||||
<h6>Wallet name <small>(optional)</small></h6>
|
||||
<input type="text" class="form-control" ng-model="walletName">
|
||||
</div>
|
||||
<div class="large-6 large-centered columns m30v">
|
||||
<h6>Your name (optional)</h6>
|
||||
<input ng-model="myNickname" placeholder="" class="size-24" style="width:100%">
|
||||
<h6>Your name <small>(optional)</small></h6>
|
||||
<input type="text" class="form-control" ng-model="myNickname">
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="row">
|
||||
<div class="large-12 columns line-dashed">
|
||||
<button class="button primary radius right" type="button"
|
||||
ng-click="create(totalCopayers, requiredCopayers, walletName, myNickname)">
|
||||
ng-click="create()">
|
||||
Create {{requiredCopayers}}-of-{{totalCopayers}} wallet
|
||||
</button>
|
||||
<a class="button secondary radius" href="#signin">Go back</a>
|
||||
|
|
@ -292,7 +284,7 @@
|
|||
</div>
|
||||
</div>
|
||||
</script>
|
||||
|
||||
|
||||
<!-- TRANSACTIONS -->
|
||||
<script type="text/ng-template" id="transactions.html">
|
||||
<div class="transactions" data-ng-controller="TransactionsController">
|
||||
|
|
@ -537,6 +529,8 @@
|
|||
<script src="lib/angular-foundation/mm-foundation-tpls.min.js"></script>
|
||||
<script src="lib/peerjs/peer.js"></script>
|
||||
<script src="lib/bitcore.js"></script>
|
||||
<script src="lib/crypto-js/rollups/sha256.js"></script>
|
||||
<script src="lib/crypto-js/rollups/pbkdf2.js"></script>
|
||||
<script src="lib/crypto-js/rollups/aes.js"></script>
|
||||
<script src="lib/file-saver/FileSaver.js"></script>
|
||||
<script src="lib/socket.io.js"></script>
|
||||
|
|
@ -551,6 +545,7 @@
|
|||
<script src="js/services/video.js"></script>
|
||||
<script src="js/services/walletFactory.js"></script>
|
||||
<script src="js/services/controllerUtils.js"></script>
|
||||
<script src="js/services/passphrase.js"></script>
|
||||
|
||||
<script src="js/controllers/header.js"></script>
|
||||
<script src="js/controllers/footer.js"></script>
|
||||
|
|
|
|||
|
|
@ -20,7 +20,8 @@ var copayApp = window.copayApp = angular.module('copay',[
|
|||
'copay.setup',
|
||||
'copay.directives',
|
||||
'copay.video',
|
||||
'copay.import'
|
||||
'copay.import',
|
||||
'copay.passphrase'
|
||||
]);
|
||||
|
||||
angular.module('copay.header', []);
|
||||
|
|
@ -37,4 +38,5 @@ angular.module('copay.socket', []);
|
|||
angular.module('copay.directives', []);
|
||||
angular.module('copay.video', []);
|
||||
angular.module('copay.import', []);
|
||||
angular.module('copay.passphrase', []);
|
||||
|
||||
|
|
|
|||
|
|
@ -1,9 +1,10 @@
|
|||
'use strict';
|
||||
|
||||
angular.module('copay.setup').controller('SetupController',
|
||||
function($scope, $rootScope, $location, walletFactory, controllerUtils) {
|
||||
function($scope, $rootScope, $location, walletFactory, controllerUtils, Passphrase) {
|
||||
|
||||
$scope.loading = false;
|
||||
$scope.walletPassword = $rootScope.walletPassword;
|
||||
|
||||
// ng-repeat defined number of times instead of repeating over array?
|
||||
$scope.getNumber = function(num) {
|
||||
|
|
@ -31,15 +32,18 @@ angular.module('copay.setup').controller('SetupController',
|
|||
updateRCSelect(tc);
|
||||
});
|
||||
|
||||
$scope.create = function(totalCopayers, requiredCopayers, walletName, myNickname) {
|
||||
$scope.create = function() {
|
||||
$scope.loading = true;
|
||||
|
||||
var passphrase = Passphrase.getBase64($scope.walletPassword);
|
||||
|
||||
var opts = {
|
||||
requiredCopayers: requiredCopayers,
|
||||
totalCopayers: totalCopayers,
|
||||
name: walletName,
|
||||
nickname: myNickname,
|
||||
requiredCopayers: $scope.requiredCopayers,
|
||||
totalCopayers: $scope.totalCopayers,
|
||||
name: $scope.walletName,
|
||||
nickname: $scope.myNickname,
|
||||
passphrase: passphrase,
|
||||
};
|
||||
console.log('[setup.js.31:opts:]',opts); //TODO
|
||||
var w = walletFactory.create(opts);
|
||||
controllerUtils.startNetwork(w);
|
||||
};
|
||||
|
|
|
|||
|
|
@ -1,43 +1,54 @@
|
|||
'use strict';
|
||||
|
||||
angular.module('copay.signin').controller('SigninController',
|
||||
function($scope, $rootScope, $location, walletFactory, controllerUtils) {
|
||||
function($scope, $rootScope, $location, walletFactory, controllerUtils, Passphrase) {
|
||||
$scope.loading = false;
|
||||
$scope.wallets = walletFactory.getWallets();
|
||||
$scope.selectedWalletId = $scope.wallets.length ? $scope.wallets[0].id : null;
|
||||
$scope.openPassword = '';
|
||||
|
||||
$scope.create = function(walletName) {
|
||||
$scope.create = function() {
|
||||
$scope.loading = true;
|
||||
$rootScope.walletName = walletName;
|
||||
|
||||
$rootScope.walletName = $scope.walletName;
|
||||
$rootScope.walletPassword = $scope.createPassword;
|
||||
$location.path('setup');
|
||||
};
|
||||
|
||||
$scope.open = function(walletId, opts) {
|
||||
$scope.loading = true;
|
||||
var w = walletFactory.open(walletId, opts);
|
||||
controllerUtils.startNetwork(w);
|
||||
$scope.open = function() {
|
||||
if ($scope.openPassword != '') {
|
||||
$scope.loading = true;
|
||||
|
||||
var passphrase = Passphrase.getBase64($scope.openPassword);
|
||||
var w = walletFactory.open($scope.selectedWalletId, { passphrase: passphrase});
|
||||
controllerUtils.startNetwork(w);
|
||||
}
|
||||
};
|
||||
|
||||
$scope.join = function(secret, nickname ) {
|
||||
$scope.join = function() {
|
||||
$scope.loading = true;
|
||||
|
||||
walletFactory.network.on('badSecret', function() {
|
||||
});
|
||||
|
||||
walletFactory.joinCreateSession(secret, nickname, function(err,w) {
|
||||
walletFactory.joinCreateSession($scope.connectionId, $scope.nickname, function(err,w) {
|
||||
$scope.loading = false;
|
||||
|
||||
if (err || !w) {
|
||||
if (err || !w || !$scope.joinPassword) {
|
||||
if (err === 'joinError')
|
||||
$rootScope.flashMessage = { message: 'Can not find peer'};
|
||||
else if (err === 'badSecret')
|
||||
$rootScope.flashMessage = { message: 'Bad secret secret string', type: 'error'};
|
||||
else if (!$scope.joinPassword)
|
||||
$rootScope.flashMessage = { message: 'Enter your wallet password', type: 'error' };
|
||||
else
|
||||
$rootScope.flashMessage = { message: 'Unknown error', type: 'error'};
|
||||
controllerUtils.onErrorDigest();
|
||||
}
|
||||
else
|
||||
} else {
|
||||
var passphrase = Passphrase.getBase64($scope.joinPassword);
|
||||
w.storage._setPassphrase(passphrase);
|
||||
controllerUtils.startNetwork(w);
|
||||
}
|
||||
});
|
||||
};
|
||||
});
|
||||
|
|
|
|||
24
js/models/core/Passphrase.js
Normal file
24
js/models/core/Passphrase.js
Normal file
|
|
@ -0,0 +1,24 @@
|
|||
'use strict';
|
||||
|
||||
function Passphrase(config) {
|
||||
config = config || {};
|
||||
this.salt = config.storageSalt;
|
||||
this.iterations = config.iterations || 1000;
|
||||
};
|
||||
|
||||
Passphrase.prototype.get = function(password) {
|
||||
var hash = CryptoJS.SHA256(CryptoJS.SHA256(password));
|
||||
var salt = CryptoJS.enc.Base64.parse(this.salt);
|
||||
var key512 = CryptoJS.PBKDF2(hash, salt, { keySize: 512/32, iterations: this.iterations });
|
||||
|
||||
return key512;
|
||||
};
|
||||
|
||||
Passphrase.prototype.getBase64 = function(password) {
|
||||
var key512 = this.get(password);
|
||||
var keyBase64 = key512.toString(CryptoJS.enc.Base64);
|
||||
|
||||
return keyBase64;
|
||||
};
|
||||
|
||||
module.exports = Passphrase;
|
||||
|
|
@ -86,7 +86,6 @@ WalletFactory.prototype.read = function(walletId) {
|
|||
};
|
||||
|
||||
WalletFactory.prototype.create = function(opts) {
|
||||
var s = WalletFactory.storage;
|
||||
opts = opts || {};
|
||||
this.log('### CREATING NEW WALLET.' +
|
||||
(opts.id ? ' USING ID: ' + opts.id : ' NEW ID') +
|
||||
|
|
@ -112,6 +111,8 @@ WalletFactory.prototype.create = function(opts) {
|
|||
});
|
||||
this.log('\t### TxProposals Initialized');
|
||||
|
||||
this.storage._setPassphrase(opts.passphrase);
|
||||
|
||||
opts.storage = this.storage;
|
||||
opts.network = this.network;
|
||||
opts.blockchain = this.blockchain;
|
||||
|
|
@ -126,12 +127,15 @@ WalletFactory.prototype.create = function(opts) {
|
|||
};
|
||||
|
||||
WalletFactory.prototype.open = function(walletId, opts) {
|
||||
this.log('Opening walletId:' + walletId);
|
||||
opts = opts || {};
|
||||
opts.id = walletId;
|
||||
opts.verbose = this.verbose;
|
||||
|
||||
this.storage._setPassphrase(opts.passphrase);
|
||||
|
||||
var w = this.read(walletId) || this.create(opts);
|
||||
w.store();
|
||||
|
||||
return w;
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -1,8 +1,6 @@
|
|||
'use strict';
|
||||
|
||||
var imports = require('soop').imports();
|
||||
//var buffertools = imports.buffertools || require('buffertools');
|
||||
var parent = imports.parent || require('./LocalPlain');
|
||||
|
||||
var id = 0;
|
||||
function Storage(opts) {
|
||||
|
|
@ -13,8 +11,6 @@ function Storage(opts) {
|
|||
if (opts.password)
|
||||
this._setPassphrase(opts.password);
|
||||
}
|
||||
Storage.parent = parent;
|
||||
|
||||
|
||||
var pps = {};
|
||||
Storage.prototype._getPassphrase = function() {
|
||||
|
|
@ -58,38 +54,105 @@ Storage.prototype._read = function(k) {
|
|||
console.log('Error while decrypting: '+e);
|
||||
throw e;
|
||||
};
|
||||
|
||||
return ret;
|
||||
};
|
||||
|
||||
Storage.prototype._write = function(k,v) {
|
||||
v = JSON.stringify(v);
|
||||
v = this._encrypt(v);
|
||||
|
||||
localStorage.setItem(k, v);
|
||||
};
|
||||
|
||||
// get value by key
|
||||
Storage.prototype.getGlobal = function(k) {
|
||||
return localStorage.getItem(k);
|
||||
};
|
||||
|
||||
// set value for key
|
||||
Storage.prototype.setGlobal = function(k,v) {
|
||||
localStorage.setItem(k, JSON.stringify(v));
|
||||
};
|
||||
|
||||
// remove value for key
|
||||
Storage.prototype.removeGlobal = function(k) {
|
||||
localStorage.removeItem(k);
|
||||
};
|
||||
|
||||
Storage.prototype._key = function(walletId, k) {
|
||||
return walletId + '::' + k;
|
||||
};
|
||||
// get value by key
|
||||
Storage.prototype.get = function(walletId, k) {
|
||||
var ret = this._read(this._key(walletId,k));
|
||||
|
||||
return ret;
|
||||
};
|
||||
|
||||
// set value for key
|
||||
Storage.prototype.set = function(walletId, k,v) {
|
||||
this._write(this._key(walletId,k), v);
|
||||
};
|
||||
|
||||
// remove value for key
|
||||
Storage.prototype.remove = function(walletId, k) {
|
||||
this.removeGlobal(this._key(walletId,k));
|
||||
};
|
||||
|
||||
Storage.prototype.setName = function(walletId, name) {
|
||||
this.setGlobal('nameFor::'+walletId, name);
|
||||
};
|
||||
|
||||
Storage.prototype.getName = function(walletId) {
|
||||
return this.getGlobal('nameFor::'+walletId);
|
||||
};
|
||||
|
||||
Storage.prototype.getWalletIds = function() {
|
||||
var walletIds = [];
|
||||
var uniq = {};
|
||||
for (var i = 0; i < localStorage.length; i++) {
|
||||
var key = localStorage.key(i);
|
||||
var split = key.split('::');
|
||||
if (split.length == 2) {
|
||||
var walletId = split[0];
|
||||
|
||||
if (walletId === 'nameFor') continue;
|
||||
|
||||
if (typeof uniq[walletId] === 'undefined' ) {
|
||||
walletIds.push(walletId);
|
||||
uniq[walletId] = 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
return walletIds;
|
||||
};
|
||||
|
||||
Storage.prototype.getWallets = function() {
|
||||
var wallets = [];
|
||||
var uniq = {};
|
||||
var ids = this.getWalletIds();
|
||||
|
||||
for (var i in ids){
|
||||
wallets.push({
|
||||
id:ids[i],
|
||||
name: this.getName(ids[i]),
|
||||
});
|
||||
}
|
||||
return wallets;
|
||||
};
|
||||
|
||||
//obj contains keys to be set
|
||||
Storage.prototype.setFromObj = function(walletId, obj) {
|
||||
for (var i in keys) {
|
||||
var key = keys[0];
|
||||
obj[key] = this.get(walletId, key);
|
||||
for (var k in obj) {
|
||||
this.set(walletId, k, obj[k]);
|
||||
}
|
||||
this.setName(walletId, obj.opts.name);
|
||||
};
|
||||
|
||||
Storage.prototype.setFromEncryptedObj = function(walletId, base64) {
|
||||
|
||||
};
|
||||
|
||||
Storage.prototype.getEncryptedObj = function(walletId) {
|
||||
var keys = this._getWalletKeys();
|
||||
var obj = {};
|
||||
for (var i in keys) {
|
||||
var key = keys[0];
|
||||
obj[key] = this.get(walletId, key);
|
||||
}
|
||||
|
||||
var str = JSON.stringify(obj);
|
||||
var base64 = this._encrypt(str).toString();
|
||||
|
||||
return base64;
|
||||
// remove all values
|
||||
Storage.prototype.clearAll = function() {
|
||||
localStorage.clear();
|
||||
};
|
||||
|
||||
module.exports = require('soop')(Storage);
|
||||
|
|
|
|||
7
js/services/passphrase.js
Normal file
7
js/services/passphrase.js
Normal file
|
|
@ -0,0 +1,7 @@
|
|||
'use strict';
|
||||
|
||||
var passphrase;
|
||||
angular.module('copay.passphrase').factory('Passphrase', function($rootScope) {
|
||||
passphrase = passphrase || new copay.Passphrase(config);
|
||||
return passphrase;
|
||||
});
|
||||
|
|
@ -3,6 +3,10 @@ var FakeStorage = function(){
|
|||
this.storage = {};
|
||||
};
|
||||
|
||||
FakeStorage.prototype._setPassphrase = function (password) {
|
||||
this.storage.passphrase = password;
|
||||
};
|
||||
|
||||
FakeStorage.prototype.setGlobal = function (id, payload) {
|
||||
this.storage[id] = payload;
|
||||
};
|
||||
|
|
|
|||
|
|
@ -32,6 +32,7 @@ describe('WalletFactory model', function() {
|
|||
port: 80
|
||||
},
|
||||
networkName: 'testnet',
|
||||
passphrase: 'test',
|
||||
};
|
||||
|
||||
it('should create the factory', function() {
|
||||
|
|
|
|||
|
|
@ -68,7 +68,9 @@ var createBundle = function(opts) {
|
|||
b.require('./js/models/core/PublicKeyRing', {
|
||||
expose: '../js/models/core/PublicKeyRing'
|
||||
});
|
||||
|
||||
b.require('./js/models/core/Passphrase', {
|
||||
expose: '../js/models/core/Passphrase'
|
||||
});
|
||||
|
||||
if (!opts.dontminify) {
|
||||
b.transform({
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue