web/satellite: save passphrase hash in local storage
WHAT: store passphrase's hash in browser local storage WHY: to make user use the same passphrase Change-Id: I3d5e601a0257a7c900e8a0ce3cdce953f1174830
This commit is contained in:
parent
9e20cfb6e0
commit
cff1052bca
9
web/satellite/package-lock.json
generated
9
web/satellite/package-lock.json
generated
@ -1773,6 +1773,15 @@
|
|||||||
"integrity": "sha512-//oorEZjL6sbPcKUaCdIGlIUeH26mgzimjBB77G6XRgnDl/L5wOnpyBGRe/Mmf5CVW3PwEBE1NjiMZ/ssFh4wA==",
|
"integrity": "sha512-//oorEZjL6sbPcKUaCdIGlIUeH26mgzimjBB77G6XRgnDl/L5wOnpyBGRe/Mmf5CVW3PwEBE1NjiMZ/ssFh4wA==",
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
|
"@types/pbkdf2": {
|
||||||
|
"version": "3.1.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/@types/pbkdf2/-/pbkdf2-3.1.0.tgz",
|
||||||
|
"integrity": "sha512-Cf63Rv7jCQ0LaL8tNXmEyqTHuIJxRdlS5vMh1mj5voN4+QFhVZnlZruezqpWYDiJ8UTzhP0VmeLXCmBk66YrMQ==",
|
||||||
|
"dev": true,
|
||||||
|
"requires": {
|
||||||
|
"@types/node": "*"
|
||||||
|
}
|
||||||
|
},
|
||||||
"@types/q": {
|
"@types/q": {
|
||||||
"version": "1.5.4",
|
"version": "1.5.4",
|
||||||
"resolved": "https://registry.npmjs.org/@types/q/-/q-1.5.4.tgz",
|
"resolved": "https://registry.npmjs.org/@types/q/-/q-1.5.4.tgz",
|
||||||
|
@ -20,6 +20,7 @@
|
|||||||
"graphql": "15.3.0",
|
"graphql": "15.3.0",
|
||||||
"graphql-tag": "2.11.0",
|
"graphql-tag": "2.11.0",
|
||||||
"load-script": "1.0.0",
|
"load-script": "1.0.0",
|
||||||
|
"pbkdf2": "3.1.1",
|
||||||
"stripe": "8.96.0",
|
"stripe": "8.96.0",
|
||||||
"vue": "2.6.12",
|
"vue": "2.6.12",
|
||||||
"vue-class-component": "7.2.5",
|
"vue-class-component": "7.2.5",
|
||||||
@ -33,6 +34,7 @@
|
|||||||
"@babel/core": "7.11.6",
|
"@babel/core": "7.11.6",
|
||||||
"@babel/plugin-proposal-object-rest-spread": "7.11.0",
|
"@babel/plugin-proposal-object-rest-spread": "7.11.0",
|
||||||
"@types/node": "13.11.1",
|
"@types/node": "13.11.1",
|
||||||
|
"@types/pbkdf2": "3.1.0",
|
||||||
"@types/segment-analytics": "0.0.32",
|
"@types/segment-analytics": "0.0.32",
|
||||||
"@types/vue2-datepicker": "3.3.0",
|
"@types/vue2-datepicker": "3.3.0",
|
||||||
"@vue/cli-plugin-babel": "4.5.6",
|
"@vue/cli-plugin-babel": "4.5.6",
|
||||||
|
@ -12,10 +12,14 @@
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
|
import pbkdf2 from 'pbkdf2';
|
||||||
import { Component, Vue } from 'vue-property-decorator';
|
import { Component, Vue } from 'vue-property-decorator';
|
||||||
|
|
||||||
import GeneratePassphrase from '@/components/common/GeneratePassphrase.vue';
|
import GeneratePassphrase from '@/components/common/GeneratePassphrase.vue';
|
||||||
|
|
||||||
|
import { RouteConfig } from '@/router';
|
||||||
|
import { LocalData } from '@/utils/localData';
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
components: {
|
components: {
|
||||||
GeneratePassphrase,
|
GeneratePassphrase,
|
||||||
@ -36,10 +40,21 @@ export default class CreatePassphrase extends Vue {
|
|||||||
/**
|
/**
|
||||||
* Holds on next button click logic.
|
* Holds on next button click logic.
|
||||||
*/
|
*/
|
||||||
public onNextClick(): void {
|
public async onNextClick(): Promise<void> {
|
||||||
if (this.isLoading) return;
|
if (this.isLoading) return;
|
||||||
|
|
||||||
this.isLoading = true;
|
this.isLoading = true;
|
||||||
|
|
||||||
|
const SALT = 'storj-unique-salt';
|
||||||
|
pbkdf2.pbkdf2(this.passphrase, SALT, 1, 64, (error, key) => {
|
||||||
|
if (error) return this.$notify.error(error.message);
|
||||||
|
|
||||||
|
LocalData.setUserIDPassSalt(this.$store.getters.user.id, key.toString('hex'), SALT);
|
||||||
|
});
|
||||||
|
|
||||||
|
this.isLoading = false;
|
||||||
|
|
||||||
|
await this.$router.push(RouteConfig.UploadFile.path);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
@ -14,6 +14,7 @@
|
|||||||
import { Component, Vue } from 'vue-property-decorator';
|
import { Component, Vue } from 'vue-property-decorator';
|
||||||
|
|
||||||
import { RouteConfig } from '@/router';
|
import { RouteConfig } from '@/router';
|
||||||
|
import { LocalData, UserIDPassSalt } from '@/utils/localData';
|
||||||
|
|
||||||
@Component
|
@Component
|
||||||
export default class ObjectsArea extends Vue {
|
export default class ObjectsArea extends Vue {
|
||||||
@ -21,8 +22,32 @@ export default class ObjectsArea extends Vue {
|
|||||||
* Lifecycle hook after initial render.
|
* Lifecycle hook after initial render.
|
||||||
* Chooses correct route.
|
* Chooses correct route.
|
||||||
*/
|
*/
|
||||||
public mounted(): void {
|
public async mounted(): Promise<void> {
|
||||||
this.$router.push(RouteConfig.Objects.with(RouteConfig.CreatePassphrase).path);
|
const DUPLICATE_NAV_ERROR: string = 'NavigationDuplicated';
|
||||||
|
const idPassSalt: UserIDPassSalt | null = LocalData.getUserIDPassSalt();
|
||||||
|
if (idPassSalt && idPassSalt.userId === this.$store.getters.user.id) {
|
||||||
|
try {
|
||||||
|
await this.$router.push(RouteConfig.Objects.with(RouteConfig.EnterPassphrase).path);
|
||||||
|
|
||||||
|
return;
|
||||||
|
} catch (error) {
|
||||||
|
if (error.name === DUPLICATE_NAV_ERROR) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
await this.$notify.error(error.message);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
await this.$router.push(RouteConfig.Objects.with(RouteConfig.CreatePassphrase).path);
|
||||||
|
} catch (error) {
|
||||||
|
if (error.name === DUPLICATE_NAV_ERROR) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
await this.$notify.error(error.message);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
@ -7,6 +7,7 @@
|
|||||||
export class LocalData {
|
export class LocalData {
|
||||||
private static userId: string = 'userId';
|
private static userId: string = 'userId';
|
||||||
private static selectedProjectId: string = 'selectedProjectId';
|
private static selectedProjectId: string = 'selectedProjectId';
|
||||||
|
private static userIdPassSalt: string = 'userIdPassSalt';
|
||||||
|
|
||||||
public static getUserId(): string | null {
|
public static getUserId(): string | null {
|
||||||
return localStorage.getItem(LocalData.userId);
|
return localStorage.getItem(LocalData.userId);
|
||||||
@ -31,4 +32,32 @@ export class LocalData {
|
|||||||
public static removeSelectedProjectId(): void {
|
public static removeSelectedProjectId(): void {
|
||||||
localStorage.removeItem(LocalData.selectedProjectId);
|
localStorage.removeItem(LocalData.selectedProjectId);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static getUserIDPassSalt(): UserIDPassSalt | null {
|
||||||
|
const data: string | null = localStorage.getItem(LocalData.userIdPassSalt);
|
||||||
|
if (data) {
|
||||||
|
const parsed = JSON.parse(data);
|
||||||
|
|
||||||
|
return new UserIDPassSalt(parsed.userId, parsed.passwordHash, parsed.salt);
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static setUserIDPassSalt(id: string, passwordHash: string, salt: string): void {
|
||||||
|
const data = new UserIDPassSalt(id, passwordHash, salt);
|
||||||
|
|
||||||
|
localStorage.setItem(LocalData.userIdPassSalt, JSON.stringify(data));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* UserIDPassSalt is an entity holding user id, password hash and salt to be stored in local storage.
|
||||||
|
*/
|
||||||
|
export class UserIDPassSalt {
|
||||||
|
public constructor(
|
||||||
|
public userId: string = '',
|
||||||
|
public passwordHash: string = '',
|
||||||
|
public salt: string = '',
|
||||||
|
) {}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user