web/satellite: create access grant: create passphrase step

WHAT:
create passphrase step for access grant flow

WHY:
passphare is needed to generate access grant

Change-Id: I9d0540826744d192b2e00a30fda907cc581a6e00
This commit is contained in:
VitaliiShpital 2020-11-18 17:20:29 +02:00 committed by Vitalii Shpital
parent 005b089c01
commit 4dddb6e668
12 changed files with 475 additions and 49 deletions

View File

@ -3780,6 +3780,24 @@
"file-uri-to-path": "1.0.0"
}
},
"bip39": {
"version": "3.0.3",
"resolved": "https://registry.npmjs.org/bip39/-/bip39-3.0.3.tgz",
"integrity": "sha512-P0dKrz4g0V0BjXfx7d9QNkJ/Txcz/k+hM9TnjqjUaXtuOfAvxXSw2rJw8DX0e3ZPwnK/IgDxoRqf0bvoVCqbMg==",
"requires": {
"@types/node": "11.11.6",
"create-hash": "^1.1.0",
"pbkdf2": "^3.0.9",
"randombytes": "^2.0.1"
},
"dependencies": {
"@types/node": {
"version": "11.11.6",
"resolved": "https://registry.npmjs.org/@types/node/-/node-11.11.6.tgz",
"integrity": "sha512-Exw4yUWMBXM3X+8oqzJNRqZSwUAaS4+7NdvHqQuFi/d+synz++xmX3QIf+BFqneW8N31R8Ky+sikfZUXq07ggQ=="
}
}
},
"block-stream": {
"version": "0.0.9",
"resolved": "https://registry.npmjs.org/block-stream/-/block-stream-0.0.9.tgz",
@ -4534,7 +4552,6 @@
"version": "1.0.4",
"resolved": "https://registry.npmjs.org/cipher-base/-/cipher-base-1.0.4.tgz",
"integrity": "sha512-Kkht5ye6ZGmwv40uUDZztayT2ThLQGfnj/T71N/XzeZeo3nf8foyW7zGTsPYkEya3m5f3cAypH+qe7YOrM1U2Q==",
"dev": true,
"requires": {
"inherits": "^2.0.1",
"safe-buffer": "^5.0.1"
@ -5543,7 +5560,6 @@
"version": "1.2.0",
"resolved": "https://registry.npmjs.org/create-hash/-/create-hash-1.2.0.tgz",
"integrity": "sha512-z00bCGNHDG8mHAkP7CtT1qVu+bFQUPjYq/4Iv3C3kWjTFV10zIjfSoeqXo9Asws8gwSHDGj/hl2u4OGIjapeCg==",
"dev": true,
"requires": {
"cipher-base": "^1.0.1",
"inherits": "^2.0.1",
@ -5556,7 +5572,6 @@
"version": "1.1.7",
"resolved": "https://registry.npmjs.org/create-hmac/-/create-hmac-1.1.7.tgz",
"integrity": "sha512-MJG9liiZ+ogc4TzUwuvbER1JRdgvUFSB5+VR/g5h82fGaIRWMWddtKBHi7/sVhfjQZ6SehlyhvQYrcYkaUIpLg==",
"dev": true,
"requires": {
"cipher-base": "^1.0.3",
"create-hash": "^1.1.0",
@ -7979,7 +7994,6 @@
"version": "3.1.0",
"resolved": "https://registry.npmjs.org/hash-base/-/hash-base-3.1.0.tgz",
"integrity": "sha512-1nmYp/rhMDiE7AYkDw+lLwlAzz0AntGIe51F3RfFfEqyQ3feY2eI/NcwC6umIQVOASPMsWJLJScWKSSvzL9IVA==",
"dev": true,
"requires": {
"inherits": "^2.0.4",
"readable-stream": "^3.6.0",
@ -7990,7 +8004,6 @@
"version": "3.6.0",
"resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.0.tgz",
"integrity": "sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA==",
"dev": true,
"requires": {
"inherits": "^2.0.3",
"string_decoder": "^1.1.1",
@ -8000,8 +8013,7 @@
"safe-buffer": {
"version": "5.2.1",
"resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz",
"integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==",
"dev": true
"integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ=="
}
}
},
@ -8436,8 +8448,7 @@
"inherits": {
"version": "2.0.4",
"resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz",
"integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==",
"dev": true
"integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ=="
},
"ini": {
"version": "1.3.5",
@ -10259,7 +10270,6 @@
"version": "1.3.5",
"resolved": "https://registry.npmjs.org/md5.js/-/md5.js-1.3.5.tgz",
"integrity": "sha512-xitP+WxNPcTTOgnTJcrhM0xvdPepipPSf3I8EIpGKeFLjt3PlJLIDG3u8EX53ZIubkb+5U2+3rELYpEhHhzdkg==",
"dev": true,
"requires": {
"hash-base": "^3.0.0",
"inherits": "^2.0.1",
@ -11774,7 +11784,6 @@
"version": "3.1.1",
"resolved": "https://registry.npmjs.org/pbkdf2/-/pbkdf2-3.1.1.tgz",
"integrity": "sha512-4Ejy1OPxi9f2tt1rRV7Go7zmfDQ+ZectEQz3VGUQhgq62HtIRPDyG/JtnwIxs6x3uNMwo2V7q1fMvKjb+Tnpqg==",
"dev": true,
"requires": {
"create-hash": "^1.1.2",
"create-hmac": "^1.1.4",
@ -12806,7 +12815,6 @@
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz",
"integrity": "sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==",
"dev": true,
"requires": {
"safe-buffer": "^5.1.0"
}
@ -13422,7 +13430,6 @@
"version": "2.0.2",
"resolved": "https://registry.npmjs.org/ripemd160/-/ripemd160-2.0.2.tgz",
"integrity": "sha512-ii4iagi25WusVoiC4B4lq7pbXfAp3D9v5CwfkY33vffw2+pkDjY1D8GaN7spsxvCSx8dkPqOZCEZyfxcmJG2IA==",
"dev": true,
"requires": {
"hash-base": "^3.0.0",
"inherits": "^2.0.1"
@ -13452,8 +13459,7 @@
"safe-buffer": {
"version": "5.1.2",
"resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz",
"integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==",
"dev": true
"integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g=="
},
"safe-regex": {
"version": "1.1.0",
@ -13808,7 +13814,6 @@
"version": "2.4.11",
"resolved": "https://registry.npmjs.org/sha.js/-/sha.js-2.4.11.tgz",
"integrity": "sha512-QMEp5B7cftE7APOjk5Y6xgrbWu+WkLVQwk8JNjZ8nKRciZaByEW6MubieAiToS7+dwvrjGhH8jRXz3MVd0AYqQ==",
"dev": true,
"requires": {
"inherits": "^2.0.1",
"safe-buffer": "^5.0.1"
@ -14534,7 +14539,6 @@
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz",
"integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==",
"dev": true,
"requires": {
"safe-buffer": "~5.1.0"
}
@ -16514,8 +16518,7 @@
"util-deprecate": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz",
"integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=",
"dev": true
"integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8="
},
"util.promisify": {
"version": "1.0.1",

View File

@ -16,6 +16,7 @@
"apollo-link-context": "1.0.20",
"apollo-link-error": "1.1.13",
"apollo-link-http": "1.5.17",
"bip39": "3.0.3",
"graphql": "15.3.0",
"graphql-tag": "2.11.0",
"load-script": "1.0.0",

View File

@ -12,6 +12,7 @@
width="199px"
height="44px"
class="empty-state__modal__cta"
:on-press="onCreateClick"
/>
</div>
</div>
@ -24,13 +25,22 @@ import VButton from '@/components/common/VButton.vue';
import Key from '@/../static/images/accessGrants/key.svg';
import { RouteConfig } from '@/router';
@Component({
components: {
Key,
VButton,
},
})
export default class EmptyState extends Vue {}
export default class EmptyState extends Vue {
/**
* Starts create access grant flow.
*/
public onCreateClick(): void {
this.$router.push(RouteConfig.AccessGrants.with(RouteConfig.CreateAccessGrant).with(RouteConfig.NameStep).path);
}
}
</script>
<style scoped lang="scss">

View File

@ -50,7 +50,7 @@ export default class ProgressBar extends Vue {
* Indicates if current route is on passphrase step.
*/
public get isPassphraseStep(): boolean {
return this.$route.name === RouteConfig.PassphraseStep.name;
return this.$route.name === RouteConfig.CreatePassphraseStep.name || this.$route.name === RouteConfig.EnterPassphraseStep.name;
}
/**
@ -69,7 +69,7 @@ export default class ProgressBar extends Vue {
flex-direction: column;
align-items: flex-start;
background: #f5f6fa;
height: 360px;
height: 380px;
border-radius: 6px 0 0 6px;
&__item {

View File

@ -1,4 +1,4 @@
v// Copyright (C) 2020 Storj Labs, Inc.
// Copyright (C) 2020 Storj Labs, Inc.
// See LICENSE for copying information.
<template>

View File

@ -0,0 +1,339 @@
// Copyright (C) 2020 Storj Labs, Inc.
// See LICENSE for copying information.
<template>
<div class="create-passphrase">
<BackIcon class="create-passphrase__back-icon" @click="onBackClick"/>
<h1 class="create-passphrase__title">Encryption Passphrase</h1>
<div class="create-passphrase__warning">
<WarningIcon/>
<p class="create-passphrase__warning__label" v-if="isGenerateState">Save Your Encryption Passphrase</p>
<p class="create-passphrase__warning__label" v-else>Remember This Passphrase</p>
</div>
<div class="create-passphrase__choosing">
<p class="create-passphrase__choosing__label">Choose Passphrase Type</p>
<div class="create-passphrase__choosing__right">
<p
class="create-passphrase__choosing__right__option left-option"
:class="{ active: isGenerateState }"
@click="onChooseGenerate"
>
Generate Phrase
</p>
<p
class="create-passphrase__choosing__right__option"
:class="{ active: isCreateState }"
@click="onChooseCreate"
>
Create Phrase
</p>
</div>
</div>
<div class="create-passphrase__value-area">
<div class="create-passphrase__value-area__mnemonic" v-if="isGenerateState">
<p class="create-passphrase__value-area__mnemonic__label">12-Word Mnemonic Passphrase:</p>
<div class="create-passphrase__value-area__mnemonic__container">
<p class="create-passphrase__value-area__mnemonic__container__value">{{ passphrase }}</p>
<VButton
class="create-passphrase__value-area__mnemonic__container__button"
label="Copy"
width="66px"
height="30px"
:on-press="onCopyClick"
/>
</div>
</div>
<div class="create-passphrase__value-area__password" v-else>
<HeaderedInput
class="create-passphrase__value-area__password__input"
label="Create Your Passphrase"
placeholder="Enter your passphrase here"
@setData="onChangePassphrase"
:error="errorMessage"
/>
</div>
</div>
<VButton
class="create-passphrase__next-button"
label="Next"
width="100%"
height="48px"
:on-press="onNextClick"
/>
</div>
</template>
<script lang="ts">
import * as bip39 from 'bip39';
import { Component, Vue } from 'vue-property-decorator';
import HeaderedInput from '@/components/common/HeaderedInput.vue';
import VButton from '@/components/common/VButton.vue';
import BackIcon from '@/../static/images/accessGrants/back.svg';
import WarningIcon from '@/../static/images/accessGrants/warning.svg';
import { RouteConfig } from '@/router';
@Component({
components: {
WarningIcon,
BackIcon,
VButton,
HeaderedInput,
},
})
export default class CreatePassphraseStep extends Vue {
private key: string = '';
public isGenerateState: boolean = true;
public isCreateState: boolean = false;
public passphrase: string = '';
public errorMessage: string = '';
/**
* Lifecycle hook after initial render.
* Sets local key from props value.
*/
public mounted(): void {
if (!this.$route.params.key) {
this.$router.push(RouteConfig.AccessGrants.with(RouteConfig.CreateAccessGrant.with(RouteConfig.NameStep)).path);
}
this.key = this.$route.params.key;
this.passphrase = bip39.generateMnemonic();
}
/**
* Changes state to generate passphrase.
*/
public onChooseGenerate(): void {
if (this.passphrase && this.isGenerateState) return;
this.passphrase = bip39.generateMnemonic();
this.isCreateState = false;
this.isGenerateState = true;
}
/**
* Changes state to create passphrase.
*/
public onChooseCreate(): void {
if (this.passphrase && this.isCreateState) return;
this.errorMessage = '';
this.passphrase = '';
this.isCreateState = true;
this.isGenerateState = false;
}
/**
* Holds on copy button click logic.
* Copies passphrase to clipboard.
*/
public onCopyClick(): void {
this.$copyText(this.passphrase);
this.$notify.success('Passphrase was copied successfully');
}
/**
* Changes passphrase data from input value.
* @param value
*/
public onChangePassphrase(value: string): void {
this.passphrase = value.trim();
this.errorMessage = '';
}
/**
* Holds on next button click logic.
* Generates access grant and redirects to next step.
*/
public onNextClick(): void {
if (!this.passphrase) {
this.errorMessage = 'Passphrase can`t be empty';
return;
}
// mock for now.
return;
}
/**
* Holds on back button click logic.
* Redirects to previous step.
*/
public onBackClick(): void {
this.$router.push({
name: RouteConfig.AccessGrants.with(RouteConfig.CreateAccessGrant.with(RouteConfig.PermissionsStep)).name,
params: {
key: this.key,
},
});
}
}
</script>
<style scoped lang="scss">
.create-passphrase {
height: calc(100% - 60px);
padding: 30px 65px;
max-width: 475px;
min-width: 475px;
font-family: 'font_regular', sans-serif;
font-style: normal;
display: flex;
flex-direction: column;
align-items: center;
position: relative;
&__back-icon {
position: absolute;
top: 30px;
left: 65px;
cursor: pointer;
}
&__title {
font-family: 'font_bold', sans-serif;
font-weight: bold;
font-size: 22px;
line-height: 27px;
color: #000;
margin: 0 0 30px 0;
}
&__warning {
display: flex;
align-items: center;
padding: 20px;
width: calc(100% - 40px);
background: #fff9f7;
border: 1px solid #f84b00;
margin-bottom: 30px;
border-radius: 8px;
&__label {
font-style: normal;
font-family: 'font_bold', sans-serif;
font-size: 16px;
line-height: 19px;
color: #1b2533;
margin: 0 0 0 15px;
}
}
&__choosing {
display: flex;
align-items: center;
justify-content: space-between;
width: 100%;
&__label {
font-family: 'font_bold', sans-serif;
font-size: 16px;
line-height: 21px;
color: #354049;
margin: 0;
}
&__right {
display: flex;
align-items: center;
&__option {
font-size: 14px;
line-height: 17px;
color: #768394;
margin: 0;
cursor: pointer;
border-bottom: 3px solid #fff;
}
}
}
&__value-area {
margin: 50px 0 60px 0;
min-height: 100px;
width: 100%;
display: flex;
align-items: flex-start;
&__mnemonic {
&__label {
font-family: 'font_bold', sans-serif;
font-size: 14px;
line-height: 19px;
color: #7c8794;
margin: 0 0 10px 0;
}
&__container {
display: flex;
align-items: flex-start;
background: #f5f6fa;
border-radius: 9px;
padding: 10px;
width: calc(100% - 20px);
&__value {
font-family: 'Source Code Pro', sans-serif;
font-size: 14px;
line-height: 25px;
color: #384b65;
word-break: break-word;
margin: 0;
word-spacing: 8px;
}
&__button {
margin-left: 10px;
min-width: 66px;
min-height: 30px;
}
}
}
&__password {
width: 100%;
&__input {
width: calc(100% - 8px);
}
}
}
}
.left-option {
margin-right: 15px;
}
.active {
font-family: 'font_bold', sans-serif;
color: #0068dc;
border-bottom: 3px solid #0068dc;
}
/deep/ .label-container {
&__main {
margin-bottom: 10px;
&__label {
margin: 0;
font-size: 14px;
line-height: 19px;
color: #7c8794;
font-family: 'font_bold', sans-serif;
}
&__error {
margin: 0 0 0 10px;
font-size: 14px;
line-height: 19px;
}
}
}
</style>

View File

@ -0,0 +1,44 @@
// Copyright (C) 2020 Storj Labs, Inc.
// See LICENSE for copying information.
<template>
<div class="enter-passphrase">
<h1 class="enter-passphrase__title">Encryption Passphrase</h1>
</div>
</template>
<script lang="ts">
import { Component, Vue } from 'vue-property-decorator';
import { RouteConfig } from '@/router';
@Component
export default class EnterPassphraseStep extends Vue {
public key: string = '';
/**
* Lifecycle hook after initial render.
* Sets local key from props value.
*/
public mounted(): void {
if (!this.$route.params.key) {
this.$router.push(RouteConfig.AccessGrants.with(RouteConfig.CreateAccessGrant.with(RouteConfig.NameStep)).path);
}
this.key = this.$route.params.key;
}
/**
* Holds on back button click logic.
* Redirects to previous step.
*/
public onBackClick(): void {
this.$router.push({
name: RouteConfig.AccessGrants.with(RouteConfig.CreateAccessGrant.with(RouteConfig.PermissionsStep)).name,
params: {
key: this.key,
},
});
}
}
</script>

View File

@ -1,13 +0,0 @@
// Copyright (C) 2020 Storj Labs, Inc.
// See LICENSE for copying information.
<template>
</template>
<script lang="ts">
import { Component, Vue } from 'vue-property-decorator';
@Component
export default class PassphraseStep extends Vue {}
</script>

View File

@ -54,6 +54,7 @@
width="100%"
height="48px"
:on-press="onContinueInBrowserClick"
:is-disabled="isLoading"
/>
<p class="permissions__cli-link" @click.stop="onContinueInCLIClick">
Continue in CLI
@ -90,6 +91,7 @@ export default class PermissionsStep extends Vue {
private restrictedKey: string = '';
private worker: Worker;
public isLoading: boolean = false;
public isDownload: boolean = true;
public isUpload: boolean = true;
public isList: boolean = true;
@ -144,6 +146,8 @@ export default class PermissionsStep extends Vue {
* Holds on continue in CLI button click logic.
*/
public onContinueInCLIClick(): void {
if (this.isLoading) return;
this.$router.push({
name: RouteConfig.AccessGrants.with(RouteConfig.CreateAccessGrant.with(RouteConfig.CLIStep)).name,
params: {
@ -156,6 +160,10 @@ export default class PermissionsStep extends Vue {
* Holds on continue in browser button click logic.
*/
public onContinueInBrowserClick(): void {
if (this.isLoading) return;
this.isLoading = true;
this.worker.postMessage({
'type': 'SetPermission',
'isDownload': this.isDownload,
@ -166,12 +174,28 @@ export default class PermissionsStep extends Vue {
'apiKey': this.key,
});
this.$router.push({
name: RouteConfig.AccessGrants.with(RouteConfig.CreateAccessGrant.with(RouteConfig.PassphraseStep)).name,
params: {
key: this.restrictedKey,
},
});
// Give time for web worker to return value.
setTimeout(() => {
this.isLoading = false;
// if (this.accessGrantsAmount > 1) {
// this.$router.push({
// name: RouteConfig.AccessGrants.with(RouteConfig.CreateAccessGrant.with(RouteConfig.EnterPassphraseStep)).name,
// params: {
// key: this.restrictedKey,
// },
// });
//
// return;
// }
this.$router.push({
name: RouteConfig.AccessGrants.with(RouteConfig.CreateAccessGrant.with(RouteConfig.CreatePassphraseStep)).name,
params: {
key: this.restrictedKey,
},
});
}, 1000);
}
/**
@ -188,6 +212,13 @@ export default class PermissionsStep extends Vue {
return this.storedBucketNames.length ? this.storedBucketNames : this.allBucketNames;
}
/**
* Returns amount of access grants from store.
*/
private get accessGrantsAmount(): number {
return this.$store.state.accessGrantsModule.page.accessGrants.length;
}
/**
* Returns all bucket names.
*/
@ -218,7 +249,7 @@ export default class PermissionsStep extends Vue {
&__back-icon {
position: absolute;
top: 40px;
top: 30px;
left: 65px;
cursor: pointer;
}

View File

@ -1,4 +1,4 @@
v// Copyright (C) 2020 Storj Labs, Inc.
// Copyright (C) 2020 Storj Labs, Inc.
// See LICENSE for copying information.
<template>

View File

@ -7,8 +7,9 @@ import Router, { RouteRecord } from 'vue-router';
import AccessGrants from '@/components/accessGrants/AccessGrants.vue';
import CreateAccessGrant from '@/components/accessGrants/CreateAccessGrant.vue';
import CLIStep from '@/components/accessGrants/steps/CLIStep.vue';
import CreatePassphraseStep from '@/components/accessGrants/steps/CreatePassphraseStep.vue';
import EnterPassphraseStep from '@/components/accessGrants/steps/EnterPassphraseStep.vue';
import NameStep from '@/components/accessGrants/steps/NameStep.vue';
import PassphraseStep from '@/components/accessGrants/steps/PassphraseStep.vue';
import PermissionsStep from '@/components/accessGrants/steps/PermissionsStep.vue';
import ResultStep from '@/components/accessGrants/steps/ResultStep.vue';
import UploadStep from '@/components/accessGrants/steps/UploadStep.vue';
@ -61,7 +62,8 @@ export abstract class RouteConfig {
public static CreateAccessGrant = new NavigationLink('create-grant', 'Create Access Grant');
public static NameStep = new NavigationLink('name', 'Name Access Grant');
public static PermissionsStep = new NavigationLink('permissions', 'Access Grant Permissions');
public static PassphraseStep = new NavigationLink('passphrase', 'Access Grant Passphrase');
public static CreatePassphraseStep = new NavigationLink('create-passphrase', 'Access Grant Create Passphrase');
public static EnterPassphraseStep = new NavigationLink('enter-passphrase', 'Access Grant Enter Passphrase');
public static ResultStep = new NavigationLink('result', 'Access Grant Result');
public static CLIStep = new NavigationLink('cli', 'Access Grant In CLI');
public static UploadStep = new NavigationLink('upload', 'Access Grant Upload Data');
@ -205,9 +207,14 @@ export const router = new Router({
props: true,
},
{
path: RouteConfig.PassphraseStep.path,
name: RouteConfig.PassphraseStep.name,
component: PassphraseStep,
path: RouteConfig.CreatePassphraseStep.path,
name: RouteConfig.CreatePassphraseStep.name,
component: CreatePassphraseStep,
},
{
path: RouteConfig.EnterPassphraseStep.path,
name: RouteConfig.EnterPassphraseStep.name,
component: EnterPassphraseStep,
},
{
path: RouteConfig.ResultStep.path,

View File

@ -0,0 +1,4 @@
<svg width="18" height="18" viewBox="0 0 18 18" fill="none" xmlns="http://www.w3.org/2000/svg">
<rect x="18" y="18" width="18" height="18" rx="9" transform="rotate(-180 18 18)" fill="#F84B00"/>
<path fill-rule="evenodd" clip-rule="evenodd" d="M8.99707 4.66675C8.44478 4.66675 7.99707 5.11446 7.99707 5.66675L7.99707 9.00008C7.99707 9.55237 8.44478 10.0001 8.99707 10.0001C9.54935 10.0001 9.99707 9.55237 9.99707 9.00008L9.99707 5.66675C9.99707 5.11446 9.54935 4.66675 8.99707 4.66675ZM9.00098 11C8.31062 11 7.75098 11.5596 7.75098 12.25C7.75098 12.9404 8.31062 13.5 9.00098 13.5C9.69133 13.5 10.251 12.9404 10.251 12.25C10.251 11.5596 9.69133 11 9.00098 11Z" fill="white"/>
</svg>

After

Width:  |  Height:  |  Size: 689 B