From 08137eb0006ba0a13cb8ea4ad1d40d43394f9652 Mon Sep 17 00:00:00 2001 From: Matthew Raymer Date: Fri, 7 Jul 2023 18:28:06 +0800 Subject: [PATCH 1/7] Updates to contacts UI. Sweep for buildIdentity and buildHeaders --- src/views/AccountViewView.vue | 94 ++++++++----- src/views/ContactAmountsView.vue | 48 +++---- src/views/ContactQRScanShowView.vue | 31 ++++- src/views/ContactsView.vue | 203 +++++++++++----------------- src/views/HomeView.vue | 11 +- src/views/NewEditProjectView.vue | 23 ++++ src/views/ProjectViewView.vue | 34 +++-- 7 files changed, 235 insertions(+), 209 deletions(-) diff --git a/src/views/AccountViewView.vue b/src/views/AccountViewView.vue index 4beb51065..be4603c7b 100644 --- a/src/views/AccountViewView.vue +++ b/src/views/AccountViewView.vue @@ -321,6 +321,29 @@ export default class AccountViewView extends Vue { showB64Copy = false; showPubCopy = false; + public async getIdentity(activeDid) { + await accountsDB.open(); + const accounts = await accountsDB.accounts.toArray(); + const account = R.find((acc) => acc.did === activeDid, accounts); + const identity = JSON.parse(account?.identity || "null"); + + if (!identity) { + throw new Error( + "Attempted to load Give records with no identity available.", + ); + } + return identity; + } + + public async getHeaders(identity) { + const token = await accessToken(identity); + const headers = { + "Content-Type": "application/json", + Authorization: "Bearer " + token, + }; + return headers; + } + // call fn, copy text to the clipboard, then redo fn after 2 seconds doCopyTwoSecRedo(text, fn) { fn(); @@ -356,16 +379,7 @@ export default class AccountViewView extends Vue { this.lastName = settings?.lastName || ""; this.showContactGives = !!settings?.showContactGivesInline; - await accountsDB.open(); - const accounts = await accountsDB.accounts.toArray(); - this.numAccounts = accounts.length; - const account = R.find((acc) => acc.did === this.activeDid, accounts); - const identity = JSON.parse(account?.identity || "null"); - if (!identity) { - this.limitsMessage = "No identity."; - this.loadingLimits = false; - return; - } + const identity = await this.getIdentity(this.activeDid); this.publicHex = identity.keys[0].publicKeyHex; this.publicBase64 = Buffer.from(this.publicHex, "hex").toString("base64"); this.derivationPath = identity.keys[0].meta.derivationPath; @@ -375,10 +389,21 @@ export default class AccountViewView extends Vue { }); this.checkLimits(); } catch (err) { - this.alertMessage = - "Clear your cache and start over (after data backup)."; - console.error("Telling user to clear cache at page create because:", err); - this.alertTitle = "Error Creating Account"; + if ( + err.message === + "Attempted to load Give records with no identity available." + ) { + this.limitsMessage = "No identity."; + this.loadingLimits = false; + } else { + this.alertMessage = + "Clear your cache and start over (after data backup)."; + console.error( + "Telling user to clear cache at page create because:", + err, + ); + this.alertTitle = "Error Creating Account"; + } } } @@ -424,36 +449,31 @@ export default class AccountViewView extends Vue { this.loadingLimits = true; this.limitsMessage = ""; - const url = this.apiServer + "/api/report/rateLimits"; - await accountsDB.open(); - const accounts = await accountsDB.accounts.toArray(); - const account = R.find((acc) => acc.did === this.activeDid, accounts); - const identity = JSON.parse(account?.identity || "null"); - if (!identity) { - this.limitsMessage = "No identity."; - this.loadingLimits = false; - return; - } - const token = await accessToken(identity); - const headers = { - "Content-Type": "application/json", - Authorization: "Bearer " + token, - }; - try { + const url = this.apiServer + "/api/report/rateLimits"; + const identity = await this.getIdentity(this.activeDid); + const headers = await this.getHeaders(identity); + const resp = await this.axios.get(url, { headers }); // axios throws an exception on a 400 if (resp.status === 200) { this.limits = resp.data; } } catch (error: unknown) { - const serverError = error as AxiosError; - - console.error("Bad response retrieving limits: ", serverError); - // Anybody know how to access items inside "response.data" without this? - // eslint-disable-next-line @typescript-eslint/no-explicit-any - const data: any = serverError.response?.data; - this.limitsMessage = data?.error?.message || "Bad server response."; + if ( + error.message === + "Attempted to load Give records with no identity available." + ) { + this.limitsMessage = "No identity."; + this.loadingLimits = false; + } else { + const serverError = error as AxiosError; + console.error("Bad response retrieving limits: ", serverError); + // Anybody know how to access items inside "response.data" without this? + // eslint-disable-next-line @typescript-eslint/no-explicit-any + const data: any = serverError.response?.data; + this.limitsMessage = data?.error?.message || "Bad server response."; + } } this.loadingLimits = false; diff --git a/src/views/ContactAmountsView.vue b/src/views/ContactAmountsView.vue index d400d30e1..11f327aff 100644 --- a/src/views/ContactAmountsView.vue +++ b/src/views/ContactAmountsView.vue @@ -143,7 +143,29 @@ export default class ContactsView extends Vue { alertTitle = ""; alertMessage = ""; - // 'created' hook runs when the Vue instance is first created + public async getIdentity(activeDid) { + await accountsDB.open(); + const accounts = await accountsDB.accounts.toArray(); + const account = R.find((acc) => acc.did === activeDid, accounts); + const identity = JSON.parse(account?.identity || "null"); + + if (!identity) { + throw new Error( + "Attempted to load Give records with no identity available.", + ); + } + return identity; + } + + public async getHeaders(identity) { + const token = await accessToken(identity); + const headers = { + "Content-Type": "application/json", + Authorization: "Bearer " + token, + }; + return headers; + } + async created() { try { await db.open(); @@ -166,21 +188,9 @@ export default class ContactsView extends Vue { } async loadGives(activeDid: string, contact: Contact) { - // only load the private keys temporarily when needed - await accountsDB.open(); - const accounts = await accountsDB.accounts.toArray(); - const account = R.find((acc) => acc.did === activeDid, accounts); - const identity = JSON.parse(account?.identity || "null"); - if (!identity) { - throw new Error( - "An ID is chosen but there are no keys for it so it cannot be used to talk with the service.", - ); - } - - // load all the time I have given to them try { + const identity = await this.getIdentity(this.activeDid); let result = []; - const url = this.apiServer + "/api/v2/report/gives?agentDid=" + @@ -268,15 +278,7 @@ export default class ContactsView extends Vue { }; // Create a signature using private key of identity - await accountsDB.open(); - const accounts = await accountsDB.accounts.toArray(); - const account = R.find((acc) => acc.did === this.activeDid, accounts); - const identity = JSON.parse(account?.identity || "null"); - if (!identity) { - throw new Error( - "An ID is chosen but there are no keys for it so it cannot be used to talk with the service.", - ); - } + const identity = await this.getIdentity(this.activeDid); if (identity.keys[0].privateKeyHex !== null) { // eslint-disable-next-line @typescript-eslint/no-non-null-assertion const privateKeyHex: string = identity.keys[0].privateKeyHex!; diff --git a/src/views/ContactQRScanShowView.vue b/src/views/ContactQRScanShowView.vue index feff8a6ce..db8715da2 100644 --- a/src/views/ContactQRScanShowView.vue +++ b/src/views/ContactQRScanShowView.vue @@ -50,6 +50,29 @@ export default class ContactQRScanShow extends Vue { apiServer = ""; qrValue = ""; + public async getIdentity(activeDid) { + await accountsDB.open(); + const accounts = await accountsDB.accounts.toArray(); + const account = R.find((acc) => acc.did === activeDid, accounts); + const identity = JSON.parse(account?.identity || "null"); + + if (!identity) { + throw new Error( + "Attempted to load Give records with no identity available.", + ); + } + return identity; + } + + public async getHeaders(identity) { + const token = await accessToken(identity); + const headers = { + "Content-Type": "application/json", + Authorization: "Bearer " + token, + }; + return headers; + } + async created() { await db.open(); const settings = await db.settings.get(MASTER_SETTINGS_KEY); @@ -62,13 +85,7 @@ export default class ContactQRScanShow extends Vue { if (!account) { this.alertMessage = "You have no identity yet."; } else { - const identity = JSON.parse(account?.identity || "null"); - if (!identity) { - throw new Error( - "An ID is chosen but there are no keys for it so it cannot be used to talk with the service.", - ); - } - + const identity = await this.getIdentity(this.activeDid); const publicKeyHex = identity.keys[0].publicKeyHex; const publicEncKey = Buffer.from(publicKeyHex, "hex").toString("base64"); const contactInfo = { diff --git a/src/views/ContactsView.vue b/src/views/ContactsView.vue index c77240e10..fb8144175 100644 --- a/src/views/ContactsView.vue +++ b/src/views/ContactsView.vue @@ -70,7 +70,7 @@ -