Skip to content
This repository was archived by the owner on Apr 15, 2019. It is now read-only.

Intro for passphrase generation modals - Closes 331 #359

Merged
merged 16 commits into from
Jun 12, 2017
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions features/login.feature
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ Feature: Login page
Scenario: should allow to create a new account
Given I'm on login page
When I click "new account button"
And I click on "next button"
And I 250 times move mouse randomly
And I remember passphrase, click "yes its save button", fill in missing word
And I click "ok button"
Expand Down
1 change: 1 addition & 0 deletions features/menu.feature
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ Feature: Top right menu
Scenario: should allow to set 2nd passphrase
Given I'm logged in as "second passphrase candidate"
When I click "register second passphrase" in main menu
And I click "next button"
And I 250 times move mouse randomly
And I remember passphrase, click "yes its save button", fill in missing word
And I click "ok button"
Expand Down
12 changes: 0 additions & 12 deletions src/components/login/login.js
Original file line number Diff line number Diff line change
Expand Up @@ -56,14 +56,6 @@ app.component('login', {
this.$scope.$watch(() => this.$mdMedia('xs') || this.$mdMedia('sm'), (wantsFullScreen) => {
this.$scope.customFullscreen = wantsFullScreen === true;
});

this.$scope.onSave = (primaryPass) => {
this.passConfirmSubmit(primaryPass);
};

this.$scope.$on('onSignupCancel', () => {
this.generatingNewPassphrase = false;
});
}

/**
Expand All @@ -90,10 +82,6 @@ app.component('login', {
}
}

generatePassphrase() {
this.generatingNewPassphrase = true;
}

devTestAccount() {
const peerStack = this.$location.search().peerStack || this.$cookies.get('peerStack');
if (peerStack === 'localhost') {
Expand Down
3 changes: 2 additions & 1 deletion src/components/login/login.pug
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ md-card
md-checkbox.md-primary(ng-model="$ctrl.show_passphrase", aria-label="Show passphrase") Show passphrase
md-content(layout='row', layout-align='center center')
// md-button(ng-disabled='$ctrl.generatingNewPassphrase', ng-click='$ctrl.devTestAccount()') Dev Test Account
md-button.md-primary.new-account-button(ng-disabled='$ctrl.random || $ctrl.generatingNewPassphrase', ng-click='$ctrl.generatePassphrase()') NEW ACCOUNT
md-button.md-primary.new-account-button(ng-disabled='$ctrl.random || $ctrl.generatingNewPassphrase',
data-open-dialog='new-account', data-options='{network: $ctrl.network}') NEW ACCOUNT
md-button.md-raised.md-primary.login-button(md-autofocus, ng-disabled='($ctrl.valid != undefined && $ctrl.valid !== 1) || $root.loggingIn', type='submit') Login
passphrase(ng-if='$ctrl.generatingNewPassphrase', data-on-save='onSave', data-target='primary-pass', data-ok-button-label='Login')
47 changes: 47 additions & 0 deletions src/components/login/newAccount.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
/**
* The directive to show the second passphrase form and register it using AccountApi
*
* @module app
* @submodule SetSecondPassCtrl
*/
app.component('newAccount', {
bindings: {
network: '=',
closeDialog: '&',
},
template: require('./newAccount.pug')(),
controller($scope, Account, $rootScope, $cookies,
Passphrase, $state, Peers) {
/**
* We call this after second passphrase is generated.
* Shows an alert with appropriate message in case the request fails.
*
* @param {String} passphrase - The validated passphrase to register as primary passphrase
*/
$scope.passConfirmSubmit = (passphrase) => {
$rootScope.loggingIn = true;
$scope.$emit('showLoadingBar');
Peers.setActive(this.network).then(() => {
$rootScope.loggingIn = false;
$scope.$emit('hideLoadingBar');
if (Peers.online) {
Account.set({
passphrase,
network: this.network,
});
$cookies.put('network', JSON.stringify(this.network));
$state.go($rootScope.landingUrl || 'main.transactions');
}
});
};

$scope.onSave = (passphrase) => {
$scope.passConfirmSubmit(passphrase);
};

$scope.cancel = () => {
this.closeDialog();
};
},
// controllerAs: 'md',
});
24 changes: 24 additions & 0 deletions src/components/login/newAccount.pug
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
div.dialog-primary(aria-label='Generate a primary passphrase for a new account', data-ng-init='$ctrl.step = 0')
md-toolbar
.md-toolbar-tools
h2 New Account
span(flex='')
md-button.md-icon-button(ng-click='cancel()', aria-label='Close dialog')
i.material-icons close
div(layout='row', layout-padding, layout-align="left center", data-ng-if='$ctrl.step === 0')
div(layout-margin)
i.material-icons info
p
span Please click Next, then move around your mouse randomly to generate a random passphrase.
br
br
span Note: After registration completes, your passphrase will be required for loging in to your account.
<br>
span This passphrase is not recoverable and if you lose it, you will lose access to your account forever. Please keep it safe!

md-dialog-actions(layout='row', data-ng-if='$ctrl.step === 0')
md-button.md-secondary(ng-disabled='$ctrl.loading', ng-click='cancel()') Cancel
span(flex)
md-button.md-raised.md-primary.submit-button.next-button(ng-click='$ctrl.step = 1') Next
section(data-ng-if='$ctrl.step === 1')
passphrase(data-on-save='onSave', data-label='Login')
7 changes: 5 additions & 2 deletions src/components/main/secondPass.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import './secondPass.less';
*/
app.component('setSecondPass', {
template: require('./secondPass.pug')(),
controller($scope, Account, $rootScope, dialog, AccountApi) {
controller($scope, Account, $rootScope, dialog, AccountApi, $mdDialog) {
/**
* We call this after second passphrase is generated.
* Shows an alert with appropriate message in case the request fails.
Expand Down Expand Up @@ -38,6 +38,9 @@ app.component('setSecondPass', {
$scope.onSave = (secondPass) => {
$scope.passConfirmSubmit(secondPass);
};

$scope.cancel = function () {
$mdDialog.hide();
};
},
// controllerAs: 'md',
});
25 changes: 22 additions & 3 deletions src/components/main/secondPass.pug
Original file line number Diff line number Diff line change
@@ -1,6 +1,25 @@
div.dialog-second(aria-label='Generate a second passphrase for your account')
form
div.dialog-second(aria-label='Generate a second passphrase for your account', data-ng-init='$ctrl.step = 0')
md-toolbar
.md-toolbar-tools
h2 Generate a second passphrase of your account
passphrase(data-on-save='onSave', data-target='second-pass', data-ok-button-label='Register', data-fee='5')
span(flex='')
md-button.md-icon-button(ng-click='cancel()', aria-label='Close dialog')
i.material-icons close
div(layout='row', layout-padding, layout-align="left center", data-ng-if='$ctrl.step === 0')
div(layout-margin)
i.material-icons info
p
span Please click Next, then move around your mouse randomly to generate a random passphrase.
br
br
span Note: After registration completes, your second passphrase will be required for all transactions sent from this account.
<br>
span Losing access to this passphrase will mean no funds can be sent from this account. So be sure to keep it safe!

md-dialog-actions(layout='row', data-ng-if='$ctrl.step === 0')
md-button.md-secondary(ng-disabled='$ctrl.loading', ng-click='cancel()') Cancel
span(flex)
md-button.md-raised.md-primary.submit-button.next-button(ng-click='$ctrl.step = 1') Next
section(data-ng-if='$ctrl.step === 1')
passphrase(data-on-save='onSave', data-label='Register', data-fee='5')

12 changes: 2 additions & 10 deletions src/components/passphrase/passphrase.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import './passphrase.less';

app.directive('passphrase', ($rootScope, $document, Passphrase, dialog, $mdMedia, $timeout) => {
app.directive('passphrase', ($rootScope, $document, Passphrase, dialog) => {
/* eslint no-param-reassign: ["error", { "props": false }] */
const PassphraseLink = function (scope, element, attrs) {
const bindEvents = (listener) => {
Expand All @@ -25,20 +25,12 @@ app.directive('passphrase', ($rootScope, $document, Passphrase, dialog, $mdMedia
*/
const generateAndDoubleCheck = (seed) => {
const passphrase = Passphrase.generatePassPhrase(seed);
const label = 'Save';

dialog.modal('save-passphrase', {
passphrase,
label,
label: attrs.label,
fee: attrs.fee,
'on-save': scope.onSave,
}).then(() => {
$timeout(() => {
$rootScope.$broadcast('onAfterSignup', {
passphrase,
target: attrs.target,
});
}, 100);
});
};

Expand Down
1 change: 1 addition & 0 deletions src/liskNano.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import './components/forging/forging';
import './components/header/header';
import './components/loadingBar/loadingBar';
import './components/login/login';
import './components/login/newAccount';
import './components/lsk/lsk';
import './components/main/main';
import './components/main/secondPass';
Expand Down
13 changes: 1 addition & 12 deletions test/components/login/login.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -61,21 +61,17 @@ describe('Login controller', () => {
let testPassphrase;
let account;
let $cookies;
/* eslint-disable no-unused-vars */
let $timeout;
/* eslint-enable no-unused-vars */
let $q;

beforeEach(inject((_$componentController_, _$rootScope_, _$state_,
_Passphrase_, _$cookies_, _$timeout_, _Account_, _$q_) => {
_Passphrase_, _$cookies_, _Account_, _$q_) => {
$componentController = _$componentController_;
$rootScope = _$rootScope_;
$state = _$state_;
Passphrase = _Passphrase_;
account = _Account_;
$cookies = _$cookies_;
/* eslint-disable no-unused-vars */
$timeout = _$timeout_;
/* eslint-enable no-unused-vars */
$q = _$q_;
}));
Expand All @@ -102,13 +98,6 @@ describe('Login controller', () => {
});
});

describe('generatePassphrase()', () => {
it('sets this.generatingNewPassphrase = true', () => {
controller.generatePassphrase();
expect(controller.generatingNewPassphrase).to.equal(true);
});
});

describe('passConfirmSubmit()', () => {
let peersMock;
let deferred;
Expand Down
103 changes: 103 additions & 0 deletions test/components/login/newAccount.spec.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,103 @@
const chai = require('chai');
const sinon = require('sinon');
const sinonChai = require('sinon-chai');

const expect = chai.expect;
chai.use(sinonChai);
const VALID_PASSPHRASE = 'illegal symbol search tree deposit youth mixture craft amazing tool soon unit';

describe('newAccount component', () => {
let $compile;
let $rootScope;
let $scope;
let element;

// Load the myApp module, which contains the directive
beforeEach(angular.mock.module('app'));

// Store references to $rootScope and $compile
// so they are available to all tests in this describe block
beforeEach(inject((_$compile_, _$rootScope_) => {
// The injector unwraps the underscores (_) from around the parameter names when matching
$compile = _$compile_;
$rootScope = _$rootScope_;
}));

beforeEach(() => {
$scope = $rootScope.$new();
$scope.network = {
name: 'Mainnet',
};
// Compile a piece of HTML containing the directive
element = $compile('<new-account data-network="network"></new-account>')($scope);
$scope.$digest();
});

const MODAL_TITLE_TEXT = 'New Account';
it(`should contain a heading saying "${MODAL_TITLE_TEXT}"`, () => {
expect(element.find('.dialog-primary md-toolbar h2').text()).to.equal(MODAL_TITLE_TEXT);
});

const NEXT_BUTTON_TEXT = 'Next';
it(`should contain a button titled "${NEXT_BUTTON_TEXT}"`, () => {
expect(element.find('.next-button span.ng-scope').text()).to.equal(NEXT_BUTTON_TEXT);
});
});

describe('newAccount controller', () => {
beforeEach(angular.mock.module('app'));

let $rootScope;
let $scope;
let $state;
let $componentController;
/* eslint-enable no-unused-vars */
let $q;
let peers;

beforeEach(inject((_$componentController_, _$rootScope_, _$state_, _$q_, _Peers_) => {
$componentController = _$componentController_;
$rootScope = _$rootScope_;
/* eslint-enable no-unused-vars */
$q = _$q_;
peers = _Peers_;
$state = _$state_;
}));

beforeEach(() => {
const scope = $rootScope.$new();
$componentController('newAccount', scope, {
network: { name: 'Mainnet' },
});
scope.$digest();
$scope = scope.$scope;
});

describe('passConfirmSubmit()', () => {
let peersMock;
let deferred;

beforeEach(() => {
deferred = $q.defer();
peersMock = sinon.mock(peers);
peersMock.expects('setActive').returns(deferred.promise);
peers.online = true;
});

it('redirects to main if passphrase is valid', () => {
const spy = sinon.spy($state, 'go');
$scope.passConfirmSubmit(VALID_PASSPHRASE);
deferred.resolve();
$scope.$apply();
expect(spy).to.have.been.calledWith();
});
});

describe('onSave()', () => {
it('calls the passConfirmSubmit with the generated passphrase', () => {
const spy = sinon.spy($scope, 'passConfirmSubmit');
$scope.onSave(VALID_PASSPHRASE);
expect(spy).to.have.been.calledWith(VALID_PASSPHRASE);
});
});
});
1 change: 1 addition & 0 deletions test/test.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ require('./components/delegates/vote.spec');
require('./components/forging/forging.spec');
require('./components/header/header.spec');
require('./components/login/login.spec');
require('./components/login/newAccount.spec');
require('./components/main/main.spec');
require('./components/main/secondPass.spec');
require('./components/passphrase/passphrase.spec');
Expand Down