add QR scanner for adding a contact

This commit is contained in:
2023-09-07 18:50:18 -06:00
parent 2db662c125
commit 94d9c425ad
11 changed files with 1087 additions and 21520 deletions

View File

@@ -20,6 +20,11 @@
<!-- New Contact -->
<div class="mb-4 flex">
<span class="self-center bg-slate-500 text-white px-1.5 py-1 rounded-md">
<router-link :to="{ name: 'contact-qr' }">
<fa icon="qrcode" class="fa-fw" />
</router-link>
</span>
<input
type="text"
placeholder="DID, Name, Public Key"
@@ -211,11 +216,17 @@
import { AxiosError } from "axios";
import * as didJwt from "did-jwt";
import * as R from "ramda";
import { NotificationIface } from "@/constants/app";
import { IIdentifier } from "@veramo/core";
import { accountsDB, db } from "@/db/index";
import { Contact } from "@/db/tables/contacts";
import { MASTER_SETTINGS_KEY } from "@/db/tables/settings";
import { accessToken, SimpleSigner } from "@/libs/crypto";
import {
accessToken,
getContactPayloadFromJwtUrl,
SimpleSigner,
} from "@/libs/crypto";
import {
GiveServerRecord,
GiveVerifiableCredential,
@@ -229,22 +240,16 @@ import EntityIcon from "@/components/EntityIcon.vue";
// eslint-disable-next-line @typescript-eslint/no-var-requires
const Buffer = require("buffer/").Buffer;
interface Notification {
group: string;
type: string;
title: string;
text: string;
}
@Component({
components: { QuickNav, EntityIcon },
})
export default class ContactsView extends Vue {
$notify!: (notification: Notification, timeout?: number) => void;
$notify!: (notification: NotificationIface, timeout?: number) => void;
activeDid = "";
apiServer = "";
contacts: Array<Contact> = [];
contactEndorserUrl = localStorage.getItem("contactEndorserUrl") || "";
contactInput = "";
// { "did:...": concatenated-descriptions } entry for each contact
givenByMeDescriptions: Record<string, string> = {};
@@ -279,6 +284,12 @@ export default class ContactsView extends Vue {
(a: Contact, b) => (a.name || "").localeCompare(b.name || ""),
allContacts,
);
if (this.contactEndorserUrl) {
await this.newContactFromScan(this.contactEndorserUrl);
localStorage.removeItem("contactEndorserUrl");
this.contactEndorserUrl = "";
}
}
public async getIdentity(activeDid: string) {
@@ -414,6 +425,18 @@ export default class ContactsView extends Vue {
}
async onClickNewContact(): Promise<void> {
if (!this.contactInput) {
this.$notify(
{
group: "alert",
type: "warning",
title: "No Contact",
text: "There was no contact info to add.",
},
-1,
);
return;
}
let did = this.contactInput;
let name, publicKeyBase64;
const commaPos1 = this.contactInput.indexOf(",");
@@ -432,12 +455,74 @@ export default class ContactsView extends Vue {
publicKeyBase64 = Buffer.from(publicKeyBase64, "hex").toString("base64");
}
const newContact = { did, name, publicKeyBase64 };
await db.contacts.add(newContact);
const allContacts = this.contacts.concat([newContact]);
this.contacts = R.sort(
(a: Contact, b) => (a.name || "").localeCompare(b.name || ""),
allContacts,
);
return this.addContact(newContact);
}
async newContactFromScan(url: string): Promise<void> {
const payload = getContactPayloadFromJwtUrl(url);
if (!payload) {
this.$notify(
{
group: "alert",
type: "danger",
title: "No Contact Info",
text: "The contact info could not be parsed.",
},
-1,
);
return;
} else {
return this.addContact({
did: payload.iss,
name: payload.own.name,
publicKeyBase64: payload.own.publicEncKey,
} as Contact);
}
}
async addContact(newContact: Contact) {
if (!newContact.did) {
this.$notify(
{
group: "alert",
type: "danger",
title: "Incomplete Contact",
text: "Cannot add a contact without a DID.",
},
-1,
);
return;
}
return db.contacts
.add(newContact)
.then(() => {
const allContacts = this.contacts.concat([newContact]);
this.contacts = R.sort(
(a: Contact, b) => (a.name || "").localeCompare(b.name || ""),
allContacts,
);
this.$notify(
{
group: "alert",
type: "success",
title: "Contact added",
text: newContact.name + " was added.",
},
-1,
);
})
.catch((err) => {
console.error("Error when adding contact to storage:", err);
this.$notify(
{
group: "alert",
type: "danger",
title: "Contact Not Added",
text: "An error prevented importing.",
},
-1,
);
});
}
async deleteContact(contact: Contact) {