|
|
@ -79,16 +79,25 @@ import { Component, Vue } from "vue-facing-decorator"; |
|
|
|
import { QrcodeStream } from "vue-qrcode-reader"; |
|
|
|
import { useClipboard } from "@vueuse/core"; |
|
|
|
|
|
|
|
import QuickNav from "@/components/QuickNav.vue"; |
|
|
|
import { NotificationIface } from "@/constants/app"; |
|
|
|
import { accountsDB, db } from "@/db/index"; |
|
|
|
import { MASTER_SETTINGS_KEY } from "@/db/tables/settings"; |
|
|
|
import { deriveAddress, nextDerivationPath, SimpleSigner } from "@/libs/crypto"; |
|
|
|
import QuickNav from "@/components/QuickNav.vue"; |
|
|
|
import { Account } from "@/db/tables/accounts"; |
|
|
|
import { Contact } from "@/db/tables/contacts"; |
|
|
|
import { MASTER_SETTINGS_KEY } from "@/db/tables/settings"; |
|
|
|
import { |
|
|
|
deriveAddress, |
|
|
|
getContactPayloadFromJwtUrl, |
|
|
|
nextDerivationPath, |
|
|
|
SimpleSigner, |
|
|
|
} from "@/libs/crypto"; |
|
|
|
import { |
|
|
|
CONTACT_URL_PREFIX, |
|
|
|
ENDORSER_JWT_URL_LOCATION, |
|
|
|
isDid, |
|
|
|
setVisibilityUtil, |
|
|
|
} from "@/libs/endorserServer"; |
|
|
|
|
|
|
|
import { Buffer } from "buffer/"; |
|
|
|
|
|
|
|
@Component({ |
|
|
@ -106,29 +115,12 @@ export default class ContactQRScanShow extends Vue { |
|
|
|
givenName = ""; |
|
|
|
qrValue = ""; |
|
|
|
|
|
|
|
public async getIdentity(activeDid: string) { |
|
|
|
await accountsDB.open(); |
|
|
|
const accounts = await accountsDB.accounts.toArray(); |
|
|
|
const account: Account | undefined = R.find( |
|
|
|
(acc) => acc.did === activeDid, |
|
|
|
accounts, |
|
|
|
); |
|
|
|
const identity = JSON.parse(account?.identity || "null"); |
|
|
|
|
|
|
|
if (!identity) { |
|
|
|
throw new Error( |
|
|
|
"Attempted to show contact info with no identifier available.", |
|
|
|
); |
|
|
|
} |
|
|
|
return identity; |
|
|
|
} |
|
|
|
|
|
|
|
async created() { |
|
|
|
await db.open(); |
|
|
|
const settings = await db.settings.get(MASTER_SETTINGS_KEY); |
|
|
|
this.activeDid = settings?.activeDid || ""; |
|
|
|
this.apiServer = settings?.apiServer || ""; |
|
|
|
this.givenName = settings?.firstName || ""; |
|
|
|
this.activeDid = (settings?.activeDid as string) || ""; |
|
|
|
this.apiServer = (settings?.apiServer as string) || ""; |
|
|
|
this.givenName = (settings?.firstName as string) || ""; |
|
|
|
|
|
|
|
await accountsDB.open(); |
|
|
|
const accounts = await accountsDB.accounts.toArray(); |
|
|
@ -172,25 +164,109 @@ export default class ContactQRScanShow extends Vue { |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
danger(message: string, title: string = "Error", timeout = 5000) { |
|
|
|
this.$notify( |
|
|
|
{ |
|
|
|
group: "alert", |
|
|
|
type: "danger", |
|
|
|
title: title, |
|
|
|
text: message, |
|
|
|
}, |
|
|
|
timeout, |
|
|
|
); |
|
|
|
} |
|
|
|
|
|
|
|
public async getIdentity(activeDid: string) { |
|
|
|
await accountsDB.open(); |
|
|
|
const accounts = await accountsDB.accounts.toArray(); |
|
|
|
const account: Account | undefined = R.find( |
|
|
|
(acc) => acc.did === activeDid, |
|
|
|
accounts, |
|
|
|
); |
|
|
|
const identity = JSON.parse((account?.identity as string) || "null"); |
|
|
|
|
|
|
|
if (!identity) { |
|
|
|
throw new Error( |
|
|
|
"Attempted to show contact info with no identifier available.", |
|
|
|
); |
|
|
|
} |
|
|
|
return identity; |
|
|
|
} |
|
|
|
|
|
|
|
/** |
|
|
|
* |
|
|
|
* @param content is the result of a QR scan, an array with one item with a rawValue property |
|
|
|
*/ |
|
|
|
// Unfortunately, there are not typescript definitions for the qrcode-stream component yet. |
|
|
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any |
|
|
|
onScanDetect(content: any) { |
|
|
|
async onScanDetect(content: any) { |
|
|
|
const url = content[0]?.rawValue; |
|
|
|
if (url) { |
|
|
|
let newContact: Contact; |
|
|
|
try { |
|
|
|
const payload = getContactPayloadFromJwtUrl(url); |
|
|
|
if (!payload) { |
|
|
|
this.$notify( |
|
|
|
{ |
|
|
|
group: "alert", |
|
|
|
type: "danger", |
|
|
|
title: "No Contact Info", |
|
|
|
text: "The contact info could not be parsed.", |
|
|
|
}, |
|
|
|
3000, |
|
|
|
); |
|
|
|
return; |
|
|
|
} |
|
|
|
newContact = { |
|
|
|
did: payload.iss as string, |
|
|
|
name: payload.own.name, |
|
|
|
nextPubKeyHashB64: payload.own.nextPublicEncKeyHash, |
|
|
|
profileImageUrl: payload.own.profileImageUrl, |
|
|
|
publicKeyBase64: payload.own.publicEncKey, |
|
|
|
}; |
|
|
|
if (!newContact.did) { |
|
|
|
this.danger("There is no DID.", "Incomplete Contact"); |
|
|
|
return; |
|
|
|
} |
|
|
|
if (!isDid(newContact.did)) { |
|
|
|
this.danger("The DID must begin with 'did:'", "Invalid DID"); |
|
|
|
return; |
|
|
|
} |
|
|
|
} catch (e) { |
|
|
|
console.error("Error parsing QR info:", e); |
|
|
|
this.danger("Could not parse the QR info.", "Read Error"); |
|
|
|
return; |
|
|
|
} |
|
|
|
|
|
|
|
try { |
|
|
|
localStorage.setItem("contactEndorserUrl", url); |
|
|
|
this.$router.push({ name: "contacts" }); |
|
|
|
await db.open(); |
|
|
|
await db.contacts.add(newContact); |
|
|
|
|
|
|
|
let addedMessage; |
|
|
|
if (this.activeDid) { |
|
|
|
await this.setVisibility(newContact, true); |
|
|
|
addedMessage = |
|
|
|
"They were added, and your activity is visible to them."; |
|
|
|
} else { |
|
|
|
addedMessage = "They were added."; |
|
|
|
} |
|
|
|
this.$notify( |
|
|
|
{ |
|
|
|
group: "alert", |
|
|
|
type: "success", |
|
|
|
title: "Contact Added", |
|
|
|
text: addedMessage, |
|
|
|
}, |
|
|
|
3000, |
|
|
|
); |
|
|
|
} catch (e) { |
|
|
|
console.error("Error saving contact info:", e); |
|
|
|
this.$notify( |
|
|
|
{ |
|
|
|
group: "alert", |
|
|
|
type: "warning", |
|
|
|
title: "Invalid Contact QR Code", |
|
|
|
text: "The QR code isn't in the right format.", |
|
|
|
type: "danger", |
|
|
|
title: "Contact Error", |
|
|
|
text: "Could not save contact info. Check if it already exists.", |
|
|
|
}, |
|
|
|
5000, |
|
|
|
); |
|
|
@ -199,7 +275,7 @@ export default class ContactQRScanShow extends Vue { |
|
|
|
this.$notify( |
|
|
|
{ |
|
|
|
group: "alert", |
|
|
|
type: "warning", |
|
|
|
type: "danger", |
|
|
|
title: "Invalid Contact QR Code", |
|
|
|
text: "No QR code detected with contact information.", |
|
|
|
}, |
|
|
@ -208,13 +284,29 @@ export default class ContactQRScanShow extends Vue { |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
async setVisibility(contact: Contact, visibility: boolean) { |
|
|
|
const result = await setVisibilityUtil( |
|
|
|
this.activeDid, |
|
|
|
this.apiServer, |
|
|
|
this.axios, |
|
|
|
db, |
|
|
|
contact, |
|
|
|
visibility, |
|
|
|
); |
|
|
|
if (result.error) { |
|
|
|
this.danger(result.error as string, "Error Setting Visibility"); |
|
|
|
} else if (!result.success) { |
|
|
|
console.error("Got strange result from setting visibility:", result); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any |
|
|
|
onScanError(error: any) { |
|
|
|
console.error("Scan was invalid:", error); |
|
|
|
this.$notify( |
|
|
|
{ |
|
|
|
group: "alert", |
|
|
|
type: "warning", |
|
|
|
type: "danger", |
|
|
|
title: "Invalid Scan", |
|
|
|
text: "The scan was invalid.", |
|
|
|
}, |
|
|
@ -223,6 +315,7 @@ export default class ContactQRScanShow extends Vue { |
|
|
|
} |
|
|
|
|
|
|
|
onCopyToClipboard() { |
|
|
|
//this.onScanDetect([{ rawValue: this.qrValue }]); // good for testing |
|
|
|
useClipboard() |
|
|
|
.copy(this.qrValue) |
|
|
|
.then(() => { |
|
|
|