Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Multiple accounts #224

Merged
merged 15 commits into from
Dec 13, 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
2 changes: 1 addition & 1 deletion app/src/renderer/components/common/NiFieldSeed.vue
Original file line number Diff line number Diff line change
Expand Up @@ -25,5 +25,5 @@ export default {
@require '~variables'

.ni-field.ni-field-seed
height 5rem
height 6rem
</style>
2 changes: 1 addition & 1 deletion app/src/renderer/components/common/NiHardwareState.vue
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ export default {
flex-flow column nowrap
align-items center
justify-content center
margin 0 auto
margin 1.5rem auto

height 15rem
width 15rem
Expand Down
4 changes: 3 additions & 1 deletion app/src/renderer/components/common/NiSession.vue
Original file line number Diff line number Diff line change
Expand Up @@ -179,7 +179,9 @@ export default {
&:not(.ni-form)
&.ni-form .ni-form-main
width 32rem
height 36rem
min-height 28rem
max-height 90vh
height auto

.ni-session-header
background app-fg
Expand Down
27 changes: 22 additions & 5 deletions app/src/renderer/components/common/NiSessionSignIn.vue
Original file line number Diff line number Diff line change
@@ -1,23 +1,30 @@
<template lang="pug">
.ni-session: form-struct(:submit='onSubmit').ni-session-container
.ni-session-header
a(@click="setState('welcome')"): i.material-icons arrow_back
.ni-session-title Sign In
a(@click="help"): i.material-icons help_outline
.ni-session-main
form-group(field-id='sign-in-name' field-label='Select Account')
field#sign-in-name(
type="select"
v-model="fields.signInName"
:options="accounts")
form-msg(name='Name' type='required' v-if='!$v.fields.signInName.required')

form-group(:error='$v.fields.signInPassword.$error'
field-id='sign-in-password' field-label='Password')
field#sign-in-password(
type="password"
v-model="fields.signInPassword")
form-msg(name='Password' type='required' v-if='!$v.fields.signInPassword.required')
form-msg(name='Password' type='minLength' min="10" v-if='!$v.fields.signInPassword.minLength')
form-group
a(@click="setState('delete')") Sign Out and Remove Account
.ni-session-footer
btn(icon="arrow_forward" icon-pos="right" value="Next" size="lg")
</template>

<script>
import {mapGetters} from 'vuex'
import {required, minLength} from 'vuelidate/lib/validators'
import Btn from '@nylira/vue-button'
import Field from '@nylira/vue-field'
Expand All @@ -37,6 +44,7 @@ export default {
},
data: () => ({
fields: {
signInName: '',
signInPassword: ''
}
}),
Expand All @@ -47,20 +55,29 @@ export default {
this.$v.$touch()
if (this.$v.$error) return
try {
await this.$store.dispatch('testLogin', {password: this.fields.signInPassword})
this.$store.dispatch('signIn', {password: this.fields.signInPassword})
await this.$store.dispatch('testLogin', { password: this.fields.signInPassword, account: this.fields.signInName })
this.$store.dispatch('signIn', { password: this.fields.signInPassword, account: this.fields.signInName })
this.$store.commit('setModalSession', false)
this.$store.commit('notify', { title: 'Signed In', body: `You are now signed in to your Cosmos account.` })
} catch (err) {
this.$store.commit('notifyError', { title: 'Signing In Failed', body: err.message })
}
}
},
computed: {
...mapGetters(['user']),
accounts () {
let accounts = this.user.accounts
accounts = accounts.filter((name) => name !== 'trunk')
return accounts.map((name) => ({ key: name, value: name }))
}
},
mounted () {
this.$el.querySelector('#sign-in-password').focus()
this.$el.querySelector('#sign-in-name').focus()
},
validations: () => ({
fields: {
signInName: { required },
signInPassword: { required, minLength: minLength(10) }
}
})
Expand Down
28 changes: 19 additions & 9 deletions app/src/renderer/components/common/NiSessionSignUp.vue
Original file line number Diff line number Diff line change
Expand Up @@ -5,19 +5,27 @@
.ni-session-title Create Account
a(@click="help"): i.material-icons help_outline
.ni-session-main
form-group(field-id='sign-up-name' field-label='Account Name' :error='$v.fields.signUpName.$error')
field#sign-up-name(
type="text"
placeholder="at least 5 characters"
v-model="fields.signUpName")
form-msg(name='Name' type='required' v-if='!$v.fields.signUpName.required')
form-msg(name='Name' type='minLength' min="5" v-if='!$v.fields.signUpName.minLength')

form-group(field-id='sign-up-seed' field-label='Seed (write it down)')
field-seed#sign-up-seed(v-model="fields.signUpSeed" disabled)
form-msg(body='Please back up the seed phrase for this account. These words cannot be recovered!')

form-group(:error='$v.fields.signInPassword.$error'
form-group(:error='$v.fields.signUpPassword.$error'
field-id='sign-in-password' field-label='Password')
field#sign-in-password(
type="password"
placeholder="at least 10 characters"
v-model="fields.signInPassword")
v-model="fields.signUpPassword")
form-msg(body="Create a password to secure your new account")
form-msg(name='Password' type='required' v-if='!$v.fields.signInPassword.required')
form-msg(name='Password' type='minLength' min="10" v-if='!$v.fields.signInPassword.minLength')
form-msg(name='Password' type='required' v-if='!$v.fields.signUpPassword.required')
form-msg(name='Password' type='minLength' min="10" v-if='!$v.fields.signUpPassword.minLength')

form-group(field-id="sign-up-warning" field-label=' '
:error='$v.fields.signUpWarning.$error')
Expand Down Expand Up @@ -63,8 +71,9 @@ export default {
data: () => ({
creating: true,
fields: {
signUpName: '',
signUpSeed: 'Creating seed...',
signInPassword: '',
signUpPassword: '',
signUpWarning: false,
signUpBackup: false
}
Expand All @@ -75,16 +84,16 @@ export default {
async onSubmit () {
this.$v.$touch()
if (this.$v.$error) return
let key = await this.$store.dispatch('createKey', { seedPhrase: this.fields.signUpSeed, password: this.fields.signInPassword })
let key = await this.$store.dispatch('createKey', { seedPhrase: this.fields.signUpSeed, password: this.fields.signUpPassword, name: this.fields.signUpName })
if (key) {
this.$store.commit('setModalSession', false)
this.$store.commit('notify', { title: 'Signed Up', body: 'Your account has been created.' })
this.$store.dispatch('signIn', {password: this.fields.signInPassword})
this.$store.dispatch('signIn', { password: this.fields.signUpPassword, account: this.fields.signUpName })
}
}
},
mounted () {
this.$el.querySelector('#sign-up-warning').focus()
this.$el.querySelector('#sign-up-name').focus()
this.$store.dispatch('createSeed')
.then(seedPhrase => {
this.creating = false
Expand All @@ -93,7 +102,8 @@ export default {
},
validations: () => ({
fields: {
signInPassword: { required, minLength: minLength(10) },
signUpName: { required, minLength: minLength(5) },
signUpPassword: { required, minLength: minLength(10) },
signUpWarning: { required },
signUpBackup: { required }
}
Expand Down
9 changes: 8 additions & 1 deletion app/src/renderer/components/common/NiSessionWelcome.vue
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,12 @@
.ni-session-title Welcome to Cosmos!
a(@click="help"): i.material-icons help_outline
.ni-session-main
li-session(
v-if="accountExists"
@click.native="setState('sign-in')"
icon="lock"
title="Sign in with password"
subtitle="If you have an account, choose this option")
li-session(
@click.native="setState('sign-up')"
icon="create"
Expand Down Expand Up @@ -35,7 +41,8 @@ export default {
LiSession
},
computed: {
...mapGetters(['config'])
...mapGetters(['config', 'user']),
accountExists () { return this.user.accounts.length > 0 }
},
methods: {
help () { this.$store.commit('setModalHelp', true) },
Expand Down
6 changes: 3 additions & 3 deletions app/src/renderer/components/common/NiToolBar.vue
Original file line number Diff line number Diff line change
Expand Up @@ -52,14 +52,14 @@ export default {
top 3rem
right 0

background hover
background bc
border-radius 0.25rem

line-height 2.5rem

padding 0 0.75rem

color bright
color txt
z-index 101

white-space nowrap
Expand All @@ -76,7 +76,7 @@ export default {
height 0
border-left 0.375rem solid transparent
border-right 0.375rem solid transparent
border-bottom 0.375rem solid hover
border-bottom 0.375rem solid bc

display block
content ''
Expand Down
9 changes: 6 additions & 3 deletions app/src/renderer/components/common/NiUserPane.vue
Original file line number Diff line number Diff line change
Expand Up @@ -6,12 +6,12 @@ list-item.ni-li-user(
@click.native="close"
icon="face"
title="CosmosUser01")
div(v-else-if="user.signedIn")
div(v-else-if="user.signedIn")
list-item.ni-li-user(
type="link"
icon="mood"
icon="exit_to_app"
@click.native="signOut"
title="Signed In (Sign Out)")
title="Sign Out")
list-item.ni-li-user(
v-else
@click.native="openSession"
Expand Down Expand Up @@ -59,4 +59,7 @@ export default {
border-top px solid bc
height 3rem + px
cursor: pointer

.ni-li-title
color link
</style>
2 changes: 1 addition & 1 deletion app/src/renderer/components/wallet/PageBalances.vue
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ page(title='Balance')
:key="i.denom"
:dt="i.denom.toUpperCase()"
:dd="i.amount")
list-item(v-if='wallet.balances.length === 0' dt="N/A" dd="None Available")
list-item(v-if='wallet.denoms.length === 0 && wallet.balances.length === 0' dt="N/A" dd="None Available")
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

why not use allDenomBalances.length?

</template>

<script>
Expand Down
2 changes: 1 addition & 1 deletion app/src/renderer/styles/variables.styl
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ app-bg-hover = hsl(app-hue, 33%, 20%)
// text
bright = #fff
txt = hsl(app-hue, 13%, 85%)
dim = hsl(app-hue, 13%, 69%)
dim = hsl(app-hue, 13%, 60%)

// borders
bc = hsl(app-hue, 22%, 23%)
Expand Down
38 changes: 20 additions & 18 deletions app/src/renderer/vuex/modules/user.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,3 @@
import { KEY_PASSWORD, KEY_NAME } from './wallet'

export default ({ commit, node }) => {
const emptyNomination = {
keybase: '',
Expand All @@ -20,35 +18,38 @@ export default ({ commit, node }) => {
delegation: [],
pubkey: '',
privkey: null,
signedIn: false
signedIn: false,
accounts: []
}

const state = JSON.parse(JSON.stringify(emptyUser))

const mutations = {
activateDelegation (state) {
state.delegationActive = true
},
setAccounts (state, accounts) {
state.accounts = accounts
}
}

const actions = {
async showInitialScreen ({ dispatch }) {
let exists = await dispatch('accountExists')
await dispatch('loadAccounts')
let exists = state.accounts.length > 0
let screen = exists ? 'sign-in' : 'welcome'
commit('setModalSessionState', screen)
commit('setModalSession', true)
},
async accountExists (state, account = KEY_NAME) {
async loadAccounts ({ commit }) {
try {
let keys = await node.listKeys()
return !!keys.find(key => key.name === account)
commit('setAccounts', keys.map((key) => key.name))
} catch (err) {
commit('notifyError', { title: `Couldn't read keys'`, body: err.message })
commit('notifyError', { title: `Couldn't read keys`, body: err.message })
}
},
// testing if the provided password works so we can show the user early if he uses the wrong password
// testing this by trying to change the password... to the same password...
async testLogin (state, {password, account = KEY_NAME}) {
async testLogin (state, { password, account }) {
try {
return await node.updateKey(account, {
name: account,
Expand All @@ -62,41 +63,42 @@ export default ({ commit, node }) => {
// to create a temporary seed phrase, we create a junk account with name 'trunk' for now
async createSeed ({ commit }) {
let JUNK_ACCOUNT_NAME = 'trunk'
let TRUNK_PASSWORD = '1234567890'
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We need to get rid of this. A malicious user could access the last generated trunk account with the standard password.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Prerequesit: cosmos/cosmos-sdk#301

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

do you mean in this PR or an another PR? this is not new — this is currently how it works...

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just a note. I commented on that, because I implemented it like that and wanted to share the thought.

try {
// cleanup an existing junk account
let keys = await node.listKeys()
if (keys.find(key => key.name === JUNK_ACCOUNT_NAME)) {
await node.deleteKey(JUNK_ACCOUNT_NAME, {
password: KEY_PASSWORD,
password: TRUNK_PASSWORD,
name: JUNK_ACCOUNT_NAME
})
}

// generate seedPhrase with junk account
let temporaryKey = await node.generateKey({ name: JUNK_ACCOUNT_NAME, password: KEY_PASSWORD })
let temporaryKey = await node.generateKey({ name: JUNK_ACCOUNT_NAME, password: TRUNK_PASSWORD })
return temporaryKey.seed_phrase
} catch (err) {
commit('notifyError', { title: 'Couln\'t create a seed', body: err.message })
commit('notifyError', { title: `Couldn't create a seed`, body: err.message })
}
},
async createKey ({ commit, dispatch }, { seedPhrase, password, name = KEY_NAME }) {
async createKey ({ commit, dispatch }, { seedPhrase, password, name }) {
try {
let {key} = await node.recoverKey({ name, password, seed_phrase: seedPhrase })
dispatch('initializeWallet', key)
return key
} catch (err) {
commit('notifyError', { title: 'Couln\'t create a key', body: err.message })
commit('notifyError', { title: `Couldn't create a key`, body: err.message })
}
},
async deleteKey ({ commit, dispatch }, { password, name = KEY_NAME }) {
async deleteKey ({ commit, dispatch }, { password, name }) {
try {
await node.deleteKey(name, { name, password })
return true
} catch (err) {
commit('notifyError', { title: `Couln't delete account ${name}`, body: err.message })
commit('notifyError', { title: `Couldn't delete account ${name}`, body: err.message })
}
},
async signIn ({ state, dispatch }, {password, account = KEY_NAME}) {
async signIn ({ state, dispatch }, { password, account }) {
state.password = password
state.account = account
state.signedIn = true
Expand Down
9 changes: 4 additions & 5 deletions app/src/renderer/vuex/modules/wallet.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,6 @@ let fs = require('fs-extra')
let { join } = require('path')
let root = require('../../../root.js')

export const KEY_NAME = 'default'
// TODO: add UI for password, instead of hardcoding one
export const KEY_PASSWORD = '1234567890'

export default ({ commit, node }) => {
let state = {
balances: [],
Expand All @@ -23,9 +19,12 @@ export default ({ commit, node }) => {
},
setWalletKey (state, key) {
state.key = key
// clear previous account state
state.balances = []
state.history = []
state.sequence = 0
},
setWalletSequence (state, sequence) {
if (state.sequence === sequence) return
state.sequence = sequence
},
setWalletHistory (state, history) {
Expand Down
Loading