mnemonicHint:'请抄写助记词,并妥善保管',
ok:'已完成'
},
+ lock: {
+ title: '安全锁定',
+ subtitle: '请输入钱包密码以解锁',
+ placeholder: '请输入密码',
+ forget: '忘记密码?',
+ import: '重新导入钱包',
+ passwordEmpty: '请输入密码',
+ passwordError: '密码错误'
+ },
protocol: {
title: '服务协议',
content: `尊敬的用户:
mnemonicHint:'Please copy the mnemonic and keep it.',
ok:'Completed'
},
+ lock: {
+ title: 'Lock',
+ subtitle: 'Please enter the password',
+ placeholder: 'password',
+ forget: 'forget password?',
+ import: 'import wallet',
+ passwordEmpty: 'Please enter the password',
+ passwordError: 'Password is wrong'
+ },
protocol: {
title: 'Service Agreement',
content:`Dear users:
case RouteNames.ENABLE:
case RouteNames.BAPP_PROMPT:
case RouteNames.PRIVACY:
- case RouteNames.PROTOCOL: return false;
- default: return true;
+ case RouteNames.PROTOCOL:
+ case RouteNames.LOCK:
+ return false;
+ default:
+ return true;
}
},
import Api from './js/api.js';
import Vue from 'vue';
-import toast from './js/Component.vue';
+import Toast from './js/Component.vue';
+export let toast
const toastInstance = {
i18n: null,
install: function (Vue, options) {
- Vue.component('v-toast', toast);
+ Vue.component('v-toast', Toast);
let methods = Api(Vue, options);
Vue.$toast = methods;
+ toast = methods;
Vue.prototype.$toast = methods;
this.i18n = options;
},
--- /dev/null
+const STORGE_KEY = 'LOCK_TIME'
+let lockTime = localStorage.getItem(STORGE_KEY)
+
+export function updateLockTime () {
+ lockTime = Date.now()
+ localStorage.setItem('LOCK_TIME', lockTime)
+}
+export function isNeedLock () {
+ const oneHour = 1000 * 60 * 60
+ return !lockTime || Date.now() - lockTime > oneHour
+}
import { Integrations } from '@sentry/tracing';
import BytomObj from "./utils/Bytom";
+import { updateLockTime, isNeedLock } from '@/models/lock'
+
store.dispatch(Actions.LOAD_BYTOM).then(() => {
Vue.use(VueI18n)
const i18n = new VueI18n({
router.beforeEach((to, from, next) => {
// wallet init
+ if (!to.meta.nolock) {
+ if (store.getters.currentAccount && isNeedLock()) {
+ next({ name: 'lock', query: { to: to.name } })
+ return
+ }
+ updateLockTime()
+ }
if (!(store.getters.currentAccount) && to.name == 'home') {
next({ name: 'welcome' })
let newURL = `${apis.runtime.getURL('pages/prompt.html')}#/welcome`;
import { Integrations } from '@sentry/tracing';
import BytomObj from "./utils/Bytom";
+import { updateLockTime, isNeedLock } from '@/models/lock'
+
store.dispatch(Actions.LOAD_BYTOM).then(() => {
Vue.use(VueI18n)
const i18n = new VueI18n({
router.beforeEach((to, from, next) => {
// wallet init
+ if (!to.meta.nolock) {
+ if (store.getters.currentAccount && isNeedLock()) {
+ next({ name: 'lock', query: { to: to.name } })
+ return
+ }
+ updateLockTime()
+ }
if (!(store.getters.currentAccount) && to.name == 'home') {
next({ name: 'welcome' })
let newURL = `${apis.runtime.getURL('pages/prompt.html')}#/welcome`;
chrome.tabs.create({ url: newURL });
return
- }else if (!(store.getters.currentAccount && store.getters.vMnemonic) && to.name == 'home') {
+ }
+ if (!(store.getters.currentAccount && store.getters.vMnemonic) && to.name == 'home') {
next({ name: 'welcome-verify-mnemonic' })
let newURL = `${apis.runtime.getURL('pages/prompt.html')}#/mnemonic`;
chrome.tabs.create({ url: newURL });
WALLETS:'wallets',
BAPP:'bapp',
BAPP_PROMPT:'bapp-prompt',
+
+ LOCK: 'lock'
};
const routers = [
{
path: '/enable',
name: RouteNames.ENABLE,
- meta: { title: '授权' },
+ meta: { title: '授权', nolock: true },
component: resolve => {
require(['@/views/prompts/authentication.vue'], resolve)
}
{
path: '/bappPrompt',
name: RouteNames.BAPP_PROMPT,
- meta: { title: 'Bapp请求' },
+ meta: { title: 'Bapp请求', nolock: true },
component: resolve => {
require(['@/views/prompts/bappPrompt.vue'], resolve)
}
{
path: '/protocol',
name: RouteNames.PROTOCOL,
- meta: { title: '用户协议' },
+ meta: { title: '用户协议', nolock: true },
component: resolve => {
require(['@/views/welcome/protocol.vue'], resolve)
}
},{
path: '/privacy',
name: RouteNames.PRIVACY,
- meta: { title: '隐私服务' },
+ meta: { title: '隐私服务', nolock: true },
component: resolve => {
require(['@/views/welcome/privacy.vue'], resolve)
}
{
path: '/welcome',
name: RouteNames.ENTRY,
- meta: { title: '创建账户' },
+ meta: { title: '创建账户', nolock: true },
component: resolve => {
require(['@/views/welcome/welcome.vue'], resolve)
}
{
path: '/creation',
name: RouteNames.CREATE_ACCOUNT,
- meta: { title: '创建账户' },
+ meta: { title: '创建账户', nolock: true },
component: resolve => {
require(['@/views/welcome/creation.vue'], resolve)
}
{
path: '/verify-mnemonic',
name: RouteNames.VERIFY_MNEMONIC,
- meta: { title: '验证助记词' },
+ meta: { title: '验证助记词', nolock: true },
component: resolve => {
require(['@/views/welcome/verifyMnemonic.vue'], resolve)
}
{
path: '/import',
name: RouteNames.RESTORE_ACCOUNT,
- meta: { title: '创建账户' },
+ meta: { title: '创建账户', nolock: true },
component: resolve => {
require(['@/views/welcome/import.vue'], resolve)
}
{
path: '/restore-password',
name: RouteNames.SETTING_PASSWORD,
- meta: { title: '密码' },
+ meta: { title: '密码', nolock: true },
component: resolve => {
require(['@/views/welcome/password/setting.vue'], resolve)
}
+ },
+ {
+ path: '/lock',
+ name: RouteNames.LOCK,
+ meta: { title: '锁屏', nolock: true },
+ component: resolve => {
+ require(['@/views/lock.vue'], resolve)
+ }
}
]
export default routers
--- /dev/null
+<template>
+ <div class="lock-page">
+ <div class="main">
+ <img class="img-lock" src="@/assets/img/locked.png" alt="">
+ <div class="title">{{ $t('lock.title') }}</div>
+ <div class="subtitle">{{ $t('lock.subtitle') }}</div>
+ <input
+ class="input"
+ type="password"
+ v-model="password"
+ :class="{ error: inputError }"
+ :placeholder="$t('lock.placeholder')"
+ @input="inputError = false"
+ @keyup.enter="onSubmit"
+ />
+ <div class="tip">
+ {{ $t('lock.forget') }} <a @click="$router.push({ name: 'welcome-import' })">{{ $t('lock.import') }}</a>
+ </div>
+ <div class="btn-submit btn btn-primary btn-round float-right" @click="onSubmit">
+ <i class="iconfont icon-right-arrow"></i>
+ </div>
+ </div>
+ <Footer />
+ </div>
+</template>
+
+<script>
+import { store } from '@/store/store'
+import { toast } from '@/components/toast'
+import account from "@/models/account"
+import { updateLockTime } from '@/models/lock'
+import { log } from 'util'
+
+export default {
+ data () {
+ return {
+ password: '',
+ inputError: false
+ }
+ },
+ computed: {
+ currentAccount: () => store.state.bytom.currentAccount
+ },
+ methods: {
+ onSubmit () {
+ if (!this.password) {
+ this.inputError = true
+ toast.error(this.$t('lock.passwordEmpty'))
+ return
+ }
+ if (!account.isValidPassword(this.currentAccount.keystore, this.password)) {
+ this.inputError = true
+ toast.error(this.$t('lock.passwordError'))
+ return
+ }
+
+ // success
+ updateLockTime()
+ this.$router.replace({ name: this.$route.query.to })
+ }
+ }
+};
+</script>
+
+<style scoped lang="scss">
+.main {
+ margin: 0 auto;
+ padding-top: 80px;
+ height: 600px;
+ width: 60%;
+ min-width: 320px;
+ max-width: 600px;
+ text-align: center;
+}
+.img-lock {
+ margin-bottom: 16px;
+ width: 72px;
+ height: 72px;
+}
+.title {
+ margin-bottom: 4px;
+ line-height: 40px;
+ font-weight: 600;
+ font-size: 28px;
+ color: rgba(0, 0, 0, 0.88);
+}
+.subtitle {
+ margin-bottom: 32px;
+ color: rgba(0, 0, 0, 0.24);
+ line-height: 24px;
+}
+.input {
+ box-sizing: border-box;
+ padding: 0 20px;
+ height: 56px;
+ width: 100%;
+ line-height: 56px;
+ outline: none;
+ border: 1px solid #EBEBEB;
+ border-radius: 8px;
+
+ &:focus {
+ border-color: #D6D6D6;
+ }
+ &::placeholder {
+ color: rgba(0, 0, 0, 0.24);
+ }
+ &.error {
+ border-color: #DF1E1E;
+ }
+}
+.tip {
+ margin-top: 8px;
+ font-size: 14px;
+ color: rgba(0, 0, 0, 0.88);
+ text-align: left;
+
+ > a {
+ color: #004EE4;
+ }
+}
+.btn-submit {
+ margin-top: 16px;
+ padding: 0;
+ line-height: 54px;
+}
+</style>
import { mapActions, mapGetters, mapState } from 'vuex'
import * as Actions from '@/store/constants';
import { required, sameAs } from "vuelidate/lib/validators";
+import { updateLockTime } from '@/models/lock';
let testNet = null;
account.createKey(this.formItem.accAlias, null, this.formItem.passwd1, this).then(() => {
loader.hide();
+ updateLockTime();
this.formItem = {};
this.$router.push('/mnemonic');
}).catch(error => {
<div>
<div class="warp bg-white">
<div class="header color-black">
- <BackButton des="welcome"/>
+ <BackButton />
<h1>
<div class="welcome-title">{{ $t('restore.title')}}</div>
</h1>
import { mapActions, mapGetters, mapState } from 'vuex'
import * as Actions from '@/store/constants';
import { required, sameAs } from "vuelidate/lib/validators";
+import { updateLockTime } from '@/models/lock';
let testNet = null;
//restore by mnemonic
account.restoreByMnemonic(accountAlias, mnemonic, this.formItem.passwd1, this).then(currentAccount => {
loader.hide();
+ updateLockTime();
this.formItem = {};
this[Actions.CLEAR_DATA]()
this[Actions.PUSH_ALERT](this.$t("successMsg.restoreWallet"))
//restore by keystore
account.restoreByKeystore(accountAlias, keystore, this.formItem.passwd1, this).then(currentAccount => {
loader.hide();
+ updateLockTime();
this.formItem = {};
this[Actions.CLEAR_DATA]()
this[Actions.PUSH_ALERT](this.$t("successMsg.restoreWallet"))