From f733e3236d9a7716e71c289f62cba9c99f4766d5 Mon Sep 17 00:00:00 2001 From: Thunder Date: Sun, 11 Jun 2023 10:05:01 +0300 Subject: [PATCH 1/5] Updating the profile manager to display the password tab only if there is credentials hashed and stored in the local storage. --- .../src/weblets/profile_manager.vue | 119 +++++++++++++++--- 1 file changed, 103 insertions(+), 16 deletions(-) diff --git a/packages/playground/src/weblets/profile_manager.vue b/packages/playground/src/weblets/profile_manager.vue index e1684ed62f..bb3c84400c 100644 --- a/packages/playground/src/weblets/profile_manager.vue +++ b/packages/playground/src/weblets/profile_manager.vue @@ -40,10 +40,7 @@ @@ -275,7 +273,12 @@ import { type Balance, createAccount, getGrid, loadBalance, loadProfile, storeSS import { normalizeError } from "../utils/helpers"; import { downloadAsFile } from "../utils/helpers"; -defineProps({ +interface Credentials { + passwordHash?: string; + mnemonicHash?: string; +} + +const props = defineProps({ modelValue: { required: false, default: () => true, @@ -284,6 +287,85 @@ defineProps({ }); defineEmits<{ (event: "update:modelValue", value: boolean): void }>(); +let mountedTimeout: any; +watch( + () => props.modelValue, + m => { + if (m) { + if (mountedTimeout) { + clearTimeout(mountedTimeout); + } + mountedTimeout = setTimeout(() => { + mounted(); + }); + } + }, +); + +function mounted() { + if (isStoredCredentials()) { + activeTab.value = 0; + const credentials: Credentials = getCredentials(); + const sessionPassword = sessionStorage.getItem("password"); + + if (!sessionPassword) return; + + password.value = sessionPassword; + + if (credentials.passwordHash) { + return login(); + } + } else { + activeTab.value = 1; + return; + } +} + +function onKeyDown() { + if (password.value.length >= 6) { + if (activeTab.value === 0) [login()]; + else { + storeAndLogin(); + } + } +} + +function getCredentials() { + const getCredentials = localStorage.getItem("wallet"); + let credentials: Credentials = {}; + + if (getCredentials) { + credentials = JSON.parse(getCredentials); + } + return credentials; +} + +function setCredentials(passwordHash: string, mnemonicHash: string): Credentials { + const credentials: Credentials = { + passwordHash: passwordHash, + mnemonicHash: mnemonicHash, + }; + localStorage.setItem("wallet", JSON.stringify(credentials)); + return credentials; +} + +function isStoredCredentials() { + return localStorage.getItem("wallet") ? true : false; +} + +function getTabs() { + let tabs = []; + if (isStoredCredentials()) { + tabs = [ + { title: "Login", value: "login" }, + { title: "Connect", value: "register" }, + ]; + } else { + tabs = [{ title: "Connect", value: "register" }]; + } + return tabs; +} + const profileManager = useProfileManager(); const mnemonic = ref(""); @@ -291,6 +373,7 @@ const isValidForm = ref(false); const SSHKeyHint = ref(""); const ssh = ref(""); let sshTimeout: any; + watch(SSHKeyHint, hint => { if (hint) { if (sshTimeout) { @@ -363,10 +446,7 @@ function validateMnInput(mnemonic: string) { } onMounted(async () => { - const maybePassword = sessionStorage.getItem("password"); - if (!maybePassword) return; - password.value = maybePassword; - login(); + mounted(); }); const creatingAccount = ref(false); @@ -424,23 +504,30 @@ async function __loadBalance(profile: Profile) { } function login() { - const mnemonicHash = localStorage.getItem(md5(password.value)) as string; - const cryptr = new Cryptr(password.value, { pbkdf2Iterations: 10, saltLength: 10 }); - const mnemonic = cryptr.decrypt(mnemonicHash); - activate(mnemonic); + const credentials: Credentials = getCredentials(); + if (credentials.mnemonicHash && credentials.passwordHash) { + if (credentials.passwordHash === md5(password.value)) { + const cryptr = new Cryptr(password.value, { pbkdf2Iterations: 10, saltLength: 10 }); + const mnemonic = cryptr.decrypt(credentials.mnemonicHash); + activate(mnemonic); + } + } } function storeAndLogin() { const cryptr = new Cryptr(password.value, { pbkdf2Iterations: 10, saltLength: 10 }); const mnemonicHash = cryptr.encrypt(mnemonic.value); - localStorage.setItem(md5(password.value), mnemonicHash); + setCredentials(md5(password.value), mnemonicHash); activate(mnemonic.value); } function validatePassword(value: string) { if (activeTab.value === 0) { - if (!localStorage.getItem(md5(value))) { - return { message: "Please provide a valid password." }; + if (!localStorage.getItem("wallet")) { + return { message: "We couldn't find a matching wallet for this password. Please connect your wallet first." }; + } + if (getCredentials().passwordHash !== md5(password.value)) { + return { message: "We couldn't find a matching wallet for this password. Please connect your wallet first." }; } } } From 18ea52b2749f63a0df99b58c321b302b7a18515c Mon Sep 17 00:00:00 2001 From: Thunder Date: Sun, 11 Jun 2023 10:37:07 +0300 Subject: [PATCH 2/5] Update the tab to be --- packages/playground/src/weblets/profile_manager.vue | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/playground/src/weblets/profile_manager.vue b/packages/playground/src/weblets/profile_manager.vue index bb3c84400c..06935dba53 100644 --- a/packages/playground/src/weblets/profile_manager.vue +++ b/packages/playground/src/weblets/profile_manager.vue @@ -358,10 +358,10 @@ function getTabs() { if (isStoredCredentials()) { tabs = [ { title: "Login", value: "login" }, - { title: "Connect", value: "register" }, + { title: "Connect your Wallet", value: "register" }, ]; } else { - tabs = [{ title: "Connect", value: "register" }]; + tabs = [{ title: "Connect your Wallet", value: "register" }]; } return tabs; } From 8c5f2222fd2abab08405a811dd74f57d85e931d5 Mon Sep 17 00:00:00 2001 From: Thunder Date: Sun, 11 Jun 2023 15:29:20 +0300 Subject: [PATCH 3/5] Fix comments, used nextTick instead of setTimeout, and removed the onKeyDown method. --- .../src/weblets/profile_manager.vue | 220 +++++++++--------- 1 file changed, 105 insertions(+), 115 deletions(-) diff --git a/packages/playground/src/weblets/profile_manager.vue b/packages/playground/src/weblets/profile_manager.vue index 06935dba53..69ec939099 100644 --- a/packages/playground/src/weblets/profile_manager.vue +++ b/packages/playground/src/weblets/profile_manager.vue @@ -51,103 +51,104 @@ " > - - - - - - - {{ createAccountError }} - - - - + + - + + +
+ + + generate account + +
+
+
+ +
+ + + {{ createAccountError }} + + + + - - - - - - - {{ loginError }} - -
- -
- - {{ activeTab === 0 ? "Login" : "Store and login" }} - -
+ + + +
+
+ + + {{ loginError }} + +
+ +
+ + {{ activeTab === 0 ? "Login" : "Store and login" }} + +
+
@@ -266,6 +267,7 @@ import { validateMnemonic } from "bip39"; import Cryptr from "cryptr"; import md5 from "md5"; import { onMounted, type Ref, ref, watch } from "vue"; +import { nextTick } from "vue"; import { generateKeyPair } from "web-ssh-keygen"; import { useProfileManager } from "../stores"; @@ -287,17 +289,11 @@ const props = defineProps({ }); defineEmits<{ (event: "update:modelValue", value: boolean): void }>(); -let mountedTimeout: any; watch( () => props.modelValue, m => { if (m) { - if (mountedTimeout) { - clearTimeout(mountedTimeout); - } - mountedTimeout = setTimeout(() => { - mounted(); - }); + nextTick().then(mounted); } }, ); @@ -321,17 +317,8 @@ function mounted() { } } -function onKeyDown() { - if (password.value.length >= 6) { - if (activeTab.value === 0) [login()]; - else { - storeAndLogin(); - } - } -} - function getCredentials() { - const getCredentials = localStorage.getItem("wallet"); + const getCredentials = localStorage.getItem(WALLET_KEY); let credentials: Credentials = {}; if (getCredentials) { @@ -345,12 +332,12 @@ function setCredentials(passwordHash: string, mnemonicHash: string): Credentials passwordHash: passwordHash, mnemonicHash: mnemonicHash, }; - localStorage.setItem("wallet", JSON.stringify(credentials)); + localStorage.setItem(WALLET_KEY, JSON.stringify(credentials)); return credentials; } function isStoredCredentials() { - return localStorage.getItem("wallet") ? true : false; + return localStorage.getItem(WALLET_KEY) ? true : false; } function getTabs() { @@ -391,6 +378,9 @@ const activeTab = ref(0); const password = ref(""); const passwordInput = ref() as Ref<{ validate(value: string): Promise }>; +const version = 1; +const WALLET_KEY = "wallet.v" + version; + let interval: any; watch( () => profileManager.profile, @@ -523,7 +513,7 @@ function storeAndLogin() { function validatePassword(value: string) { if (activeTab.value === 0) { - if (!localStorage.getItem("wallet")) { + if (!localStorage.getItem(WALLET_KEY)) { return { message: "We couldn't find a matching wallet for this password. Please connect your wallet first." }; } if (getCredentials().passwordHash !== md5(password.value)) { From 468b501fc531e2e87455d861504a810cb711b41f Mon Sep 17 00:00:00 2001 From: Thunder Date: Mon, 12 Jun 2023 10:29:53 +0300 Subject: [PATCH 4/5] Change the 'Store and login' button text to 'Connect' --- packages/playground/src/weblets/profile_manager.vue | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/playground/src/weblets/profile_manager.vue b/packages/playground/src/weblets/profile_manager.vue index 5d16a1f365..9fd5dd0052 100644 --- a/packages/playground/src/weblets/profile_manager.vue +++ b/packages/playground/src/weblets/profile_manager.vue @@ -145,7 +145,7 @@ :disabled="!isValidForm || creatingAccount" size="large" > - {{ activeTab === 0 ? "Login" : "Store and login" }} + {{ activeTab === 0 ? "Login" : "Connect" }} From 9a912348badee64957589da3aaf2d4ea1135ca31 Mon Sep 17 00:00:00 2001 From: Thunder Date: Mon, 12 Jun 2023 10:44:13 +0300 Subject: [PATCH 5/5] Clear profile manager fields when the user switches between Login and Connect. --- .../playground/src/weblets/profile_manager.vue | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/packages/playground/src/weblets/profile_manager.vue b/packages/playground/src/weblets/profile_manager.vue index 9fd5dd0052..330c5987d1 100644 --- a/packages/playground/src/weblets/profile_manager.vue +++ b/packages/playground/src/weblets/profile_manager.vue @@ -46,7 +46,7 @@ @tab:change=" () => { clearError(); - passwordInput.validate(password); + clearFields(); } " > @@ -295,6 +295,15 @@ watch( m => { if (m) { nextTick().then(mounted); + } else { + nextTick().then(() => { + if (isStoredCredentials()) { + activeTab.value = 0; + } else { + activeTab.value = 1; + } + clearFields(); + }); } }, ); @@ -412,6 +421,11 @@ function clearError() { createAccountError.value = null; } +function clearFields() { + password.value = ""; + mnemonic.value = ""; +} + async function activate(mnemonic: string) { clearError(); activating.value = true;