forked from trent_larson/crowd-funder-for-time-pwa
change all copied contact URLs to contact-import, and handle multiples & singles separately
This commit is contained in:
@@ -11,7 +11,6 @@ import {
|
|||||||
CONTACT_IMPORT_ONE_URL_PATH_TIME_SAFARI,
|
CONTACT_IMPORT_ONE_URL_PATH_TIME_SAFARI,
|
||||||
} from "@/libs/endorserServer";
|
} from "@/libs/endorserServer";
|
||||||
import { DEFAULT_DID_PROVIDER_NAME } from "../veramo/setup";
|
import { DEFAULT_DID_PROVIDER_NAME } from "../veramo/setup";
|
||||||
import { decodeEndorserJwt } from "@/libs/crypto/vc";
|
|
||||||
|
|
||||||
export const DEFAULT_ROOT_DERIVATION_PATH = "m/84737769'/0'/0'/0'";
|
export const DEFAULT_ROOT_DERIVATION_PATH = "m/84737769'/0'/0'/0'";
|
||||||
|
|
||||||
@@ -103,11 +102,9 @@ export const accessToken = async (did?: string) => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@return payload of JWT pulled out of any recognized URL path (if any) and decoded:
|
@return payload of JWT pulled out of any recognized URL path (if any)
|
||||||
{ iat: number, iss: string (DID), own: { name, publicEncKey (base64-encoded key) } }
|
|
||||||
... or an array of such as { contacts: [ contact, ... ] }
|
|
||||||
*/
|
*/
|
||||||
export const getContactPayloadFromJwtUrl = (jwtUrlText: string) => {
|
export const getContactJwtFromJwtUrl = (jwtUrlText: string) => {
|
||||||
let jwtText = jwtUrlText;
|
let jwtText = jwtUrlText;
|
||||||
const appImportConfirmUrlLoc = jwtText.indexOf(
|
const appImportConfirmUrlLoc = jwtText.indexOf(
|
||||||
CONTACT_IMPORT_CONFIRM_URL_PATH_TIME_SAFARI,
|
CONTACT_IMPORT_CONFIRM_URL_PATH_TIME_SAFARI,
|
||||||
@@ -132,11 +129,7 @@ export const getContactPayloadFromJwtUrl = (jwtUrlText: string) => {
|
|||||||
endorserUrlPathLoc + CONTACT_URL_PATH_ENDORSER_CH_OLD.length,
|
endorserUrlPathLoc + CONTACT_URL_PATH_ENDORSER_CH_OLD.length,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
return jwtText;
|
||||||
// JWT format: { header, payload, signature, data }
|
|
||||||
const jwt = decodeEndorserJwt(jwtText);
|
|
||||||
|
|
||||||
return jwt.payload;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
export const nextDerivationPath = (origDerivPath: string) => {
|
export const nextDerivationPath = (origDerivPath: string) => {
|
||||||
|
|||||||
@@ -294,7 +294,12 @@ export interface ErrorResult extends ResultWithType {
|
|||||||
|
|
||||||
export type CreateAndSubmitClaimResult = SuccessResult | ErrorResult;
|
export type CreateAndSubmitClaimResult = SuccessResult | ErrorResult;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This is similar to Contact but it grew up in different logic paths.
|
||||||
|
* We may want to change this to be a Contact.
|
||||||
|
*/
|
||||||
export interface UserInfo {
|
export interface UserInfo {
|
||||||
|
did: string;
|
||||||
name: string;
|
name: string;
|
||||||
publicEncKey: string;
|
publicEncKey: string;
|
||||||
registered: boolean;
|
registered: boolean;
|
||||||
@@ -609,7 +614,17 @@ const planCache: LRUCache<string, PlanSummaryRecord> = new LRUCache({
|
|||||||
*/
|
*/
|
||||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||||
export function errorStringForLog(error: any) {
|
export function errorStringForLog(error: any) {
|
||||||
let fullError = "" + error + " - JSON: " + JSON.stringify(error);
|
let stringifiedError = "" + error;
|
||||||
|
try {
|
||||||
|
stringifiedError = JSON.stringify(error);
|
||||||
|
} catch (e) {
|
||||||
|
// can happen with Dexie, eg:
|
||||||
|
// TypeError: Converting circular structure to JSON
|
||||||
|
// --> starting at object with constructor 'DexieError2'
|
||||||
|
// | property '_promise' -> object with constructor 'DexiePromise'
|
||||||
|
// --- property '_value' closes the circle
|
||||||
|
}
|
||||||
|
let fullError = "" + error + " - JSON: " + stringifiedError;
|
||||||
const errorResponseText = JSON.stringify(error.response);
|
const errorResponseText = JSON.stringify(error.response);
|
||||||
// for some reason, error.response is not included in stringify result (eg. for 400 errors on invite redemptions)
|
// for some reason, error.response is not included in stringify result (eg. for 400 errors on invite redemptions)
|
||||||
if (!R.empty(errorResponseText) && !fullError.includes(errorResponseText)) {
|
if (!R.empty(errorResponseText) && !fullError.includes(errorResponseText)) {
|
||||||
@@ -1112,6 +1127,7 @@ export async function generateEndorserJwtUrlForAccount(
|
|||||||
iat: Date.now(),
|
iat: Date.now(),
|
||||||
iss: account.did,
|
iss: account.did,
|
||||||
own: {
|
own: {
|
||||||
|
did: account.did,
|
||||||
name: name ?? "",
|
name: name ?? "",
|
||||||
publicEncKey,
|
publicEncKey,
|
||||||
registered: !!isRegistered,
|
registered: !!isRegistered,
|
||||||
@@ -1137,7 +1153,7 @@ export async function generateEndorserJwtUrlForAccount(
|
|||||||
|
|
||||||
const vcJwt = await createEndorserJwtForDid(account.did, contactInfo);
|
const vcJwt = await createEndorserJwtForDid(account.did, contactInfo);
|
||||||
|
|
||||||
const viewPrefix = APP_SERVER + CONTACT_IMPORT_ONE_URL_PATH_TIME_SAFARI;
|
const viewPrefix = APP_SERVER + CONTACT_IMPORT_CONFIRM_URL_PATH_TIME_SAFARI;
|
||||||
return viewPrefix + vcJwt;
|
return viewPrefix + vcJwt;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -122,7 +122,6 @@
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { JWTPayload, JWTVerified } from "did-jwt";
|
|
||||||
import * as R from "ramda";
|
import * as R from "ramda";
|
||||||
import { Component, Vue } from "vue-facing-decorator";
|
import { Component, Vue } from "vue-facing-decorator";
|
||||||
import { RouteLocationNormalizedLoaded, Router } from "vue-router";
|
import { RouteLocationNormalizedLoaded, Router } from "vue-router";
|
||||||
@@ -138,13 +137,13 @@ import {
|
|||||||
} from "@/db/index";
|
} from "@/db/index";
|
||||||
import { Contact, ContactMethod } from "@/db/tables/contacts";
|
import { Contact, ContactMethod } from "@/db/tables/contacts";
|
||||||
import * as libsUtil from "@/libs/util";
|
import * as libsUtil from "@/libs/util";
|
||||||
import { decodeAndVerifyJwt } from "@/libs/crypto/vc";
|
import { decodeEndorserJwt } from "@/libs/crypto/vc";
|
||||||
import {
|
import {
|
||||||
capitalizeAndInsertSpacesBeforeCaps,
|
capitalizeAndInsertSpacesBeforeCaps,
|
||||||
errorStringForLog,
|
errorStringForLog,
|
||||||
setVisibilityUtil,
|
setVisibilityUtil,
|
||||||
} from "@/libs/endorserServer";
|
} from "@/libs/endorserServer";
|
||||||
import { getContactPayloadFromJwtUrl } from "@/libs/crypto";
|
import { getContactJwtFromJwtUrl } from "@/libs/crypto";
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
components: { EntityIcon, OfferDialog, QuickNav },
|
components: { EntityIcon, OfferDialog, QuickNav },
|
||||||
@@ -182,7 +181,7 @@ export default class ContactImportView extends Vue {
|
|||||||
this.activeDid = settings.activeDid || "";
|
this.activeDid = settings.activeDid || "";
|
||||||
this.apiServer = settings.apiServer || "";
|
this.apiServer = settings.apiServer || "";
|
||||||
|
|
||||||
// look for any imported contacts from the query parameter
|
// look for any imported contact array from the query parameter
|
||||||
const importedContacts = (this.$route as RouteLocationNormalizedLoaded)
|
const importedContacts = (this.$route as RouteLocationNormalizedLoaded)
|
||||||
.query["contacts"] as string;
|
.query["contacts"] as string;
|
||||||
if (importedContacts) {
|
if (importedContacts) {
|
||||||
@@ -194,10 +193,36 @@ export default class ContactImportView extends Vue {
|
|||||||
/\/contact-import\/(ey.+)$/,
|
/\/contact-import\/(ey.+)$/,
|
||||||
)?.[1];
|
)?.[1];
|
||||||
if (jwt) {
|
if (jwt) {
|
||||||
// decode the JWT
|
// would prefer to validate but we've got an error with JWTs on QR codes generated in the future
|
||||||
// eslint-disable-next-line prettier/prettier
|
// eslint-disable-next-line prettier/prettier
|
||||||
const parsedJwt: Omit<JWTVerified, "didResolutionResult" | "signer" | "jwt"> = await decodeAndVerifyJwt(jwt);
|
// const parsedJwt: Omit<JWTVerified, "didResolutionResult" | "signer" | "jwt"> = await decodeAndVerifyJwt(jwt);
|
||||||
await this.setContactsSelected(parsedJwt.payload.contacts as Contact[]);
|
// decode the JWT
|
||||||
|
const parsedJwt = decodeEndorserJwt(jwt);
|
||||||
|
|
||||||
|
const contacts: Array<Contact> =
|
||||||
|
parsedJwt.payload.contacts || // someday this will be the only payload sent to this page
|
||||||
|
(Array.isArray(parsedJwt.payload) ? parsedJwt.payload : undefined);
|
||||||
|
if (!contacts && parsedJwt.payload.own) {
|
||||||
|
// handle this single-contact JWT in the contacts page, better suited to single additions
|
||||||
|
(this.$router as Router).push({
|
||||||
|
name: "contacts",
|
||||||
|
query: { contactJwt: jwt },
|
||||||
|
});
|
||||||
|
}
|
||||||
|
if (contacts) {
|
||||||
|
await this.setContactsSelected(contacts);
|
||||||
|
} else {
|
||||||
|
// no contacts found so default message should be OK
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (
|
||||||
|
this.contactsImporting.length === 1 &&
|
||||||
|
R.isEmpty(this.contactsExisting)
|
||||||
|
) {
|
||||||
|
// if there is only one contact and it's new, then we will automatically import it
|
||||||
|
this.contactsSelected[0] = true;
|
||||||
|
this.importContacts(); // ... which routes to the contacts list
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -269,7 +294,10 @@ export default class ContactImportView extends Vue {
|
|||||||
|
|
||||||
try {
|
try {
|
||||||
// (For another approach used with invites, see InviteOneAcceptView.processInvite)
|
// (For another approach used with invites, see InviteOneAcceptView.processInvite)
|
||||||
const payload: JWTPayload = getContactPayloadFromJwtUrl(jwtInput);
|
const jwt: string = getContactJwtFromJwtUrl(jwtInput);
|
||||||
|
// JWT format: { header, payload, signature, data }
|
||||||
|
const payload = decodeEndorserJwt(jwt).payload;
|
||||||
|
|
||||||
if (Array.isArray(payload.contacts)) {
|
if (Array.isArray(payload.contacts)) {
|
||||||
await this.setContactsSelected(payload.contacts);
|
await this.setContactsSelected(payload.contacts);
|
||||||
} else {
|
} else {
|
||||||
@@ -304,6 +332,7 @@ export default class ContactImportView extends Vue {
|
|||||||
updatedCount++;
|
updatedCount++;
|
||||||
} else {
|
} else {
|
||||||
// without explicit clone on the Proxy, we get: DataCloneError: Failed to execute 'add' on 'IDBObjectStore': #<Object> could not be cloned.
|
// without explicit clone on the Proxy, we get: DataCloneError: Failed to execute 'add' on 'IDBObjectStore': #<Object> could not be cloned.
|
||||||
|
// DataError: Failed to execute 'add' on 'IDBObjectStore': Evaluating the object store's key path yielded a value that is not a valid key.
|
||||||
await db.contacts.add(R.clone(contact));
|
await db.contacts.add(R.clone(contact));
|
||||||
importedCount++;
|
importedCount++;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -93,7 +93,6 @@ import { AxiosError } from "axios";
|
|||||||
import QRCodeVue3 from "qr-code-generator-vue3";
|
import QRCodeVue3 from "qr-code-generator-vue3";
|
||||||
import { Component, Vue } from "vue-facing-decorator";
|
import { Component, Vue } from "vue-facing-decorator";
|
||||||
import { QrcodeStream } from "vue-qrcode-reader";
|
import { QrcodeStream } from "vue-qrcode-reader";
|
||||||
import { Router } from "vue-router";
|
|
||||||
import { useClipboard } from "@vueuse/core";
|
import { useClipboard } from "@vueuse/core";
|
||||||
|
|
||||||
import QuickNav from "@/components/QuickNav.vue";
|
import QuickNav from "@/components/QuickNav.vue";
|
||||||
@@ -102,14 +101,14 @@ import { NotificationIface } from "@/constants/app";
|
|||||||
import { db, retrieveSettingsForActiveAccount } from "@/db/index";
|
import { db, retrieveSettingsForActiveAccount } from "@/db/index";
|
||||||
import { Contact } from "@/db/tables/contacts";
|
import { Contact } from "@/db/tables/contacts";
|
||||||
import { MASTER_SETTINGS_KEY } from "@/db/tables/settings";
|
import { MASTER_SETTINGS_KEY } from "@/db/tables/settings";
|
||||||
import { getContactPayloadFromJwtUrl } from "@/libs/crypto";
|
import { getContactJwtFromJwtUrl } from "@/libs/crypto";
|
||||||
import {
|
import {
|
||||||
generateEndorserJwtUrlForAccount,
|
generateEndorserJwtUrlForAccount,
|
||||||
isDid,
|
isDid,
|
||||||
register,
|
register,
|
||||||
setVisibilityUtil,
|
setVisibilityUtil,
|
||||||
} from "@/libs/endorserServer";
|
} from "@/libs/endorserServer";
|
||||||
import { ETHR_DID_PREFIX } from "@/libs/crypto/vc";
|
import { decodeEndorserJwt, ETHR_DID_PREFIX } from "@/libs/crypto/vc";
|
||||||
import { retrieveAccountMetadata } from "@/libs/util";
|
import { retrieveAccountMetadata } from "@/libs/util";
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
@@ -180,8 +179,8 @@ export default class ContactQRScanShow extends Vue {
|
|||||||
if (url) {
|
if (url) {
|
||||||
let newContact: Contact;
|
let newContact: Contact;
|
||||||
try {
|
try {
|
||||||
const payload = getContactPayloadFromJwtUrl(url);
|
const jwt = getContactJwtFromJwtUrl(url);
|
||||||
if (!payload) {
|
if (!jwt) {
|
||||||
this.$notify(
|
this.$notify(
|
||||||
{
|
{
|
||||||
group: "alert",
|
group: "alert",
|
||||||
@@ -193,15 +192,9 @@ export default class ContactQRScanShow extends Vue {
|
|||||||
);
|
);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (Array.isArray(payload.contacts)) {
|
const { payload } = decodeEndorserJwt(jwt);
|
||||||
// reroute to the ContactsImport
|
|
||||||
(this.$router as Router).push({
|
|
||||||
path: "/contact-import/" + url.substring(url.lastIndexOf("/") + 1),
|
|
||||||
});
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
newContact = {
|
newContact = {
|
||||||
did: payload.iss as string,
|
did: payload.own.did || payload.iss, // ".own.did" is reliable as of v 0.3.49
|
||||||
name: payload.own.name,
|
name: payload.own.name,
|
||||||
nextPubKeyHashB64: payload.own.nextPublicEncKeyHash,
|
nextPubKeyHashB64: payload.own.nextPublicEncKeyHash,
|
||||||
profileImageUrl: payload.own.profileImageUrl,
|
profileImageUrl: payload.own.profileImageUrl,
|
||||||
|
|||||||
@@ -344,7 +344,7 @@ import {
|
|||||||
updateDefaultSettings,
|
updateDefaultSettings,
|
||||||
} from "@/db/index";
|
} from "@/db/index";
|
||||||
import { Contact } from "@/db/tables/contacts";
|
import { Contact } from "@/db/tables/contacts";
|
||||||
import { getContactPayloadFromJwtUrl } from "@/libs/crypto";
|
import { getContactJwtFromJwtUrl } from "@/libs/crypto";
|
||||||
import { decodeEndorserJwt } from "@/libs/crypto/vc";
|
import { decodeEndorserJwt } from "@/libs/crypto/vc";
|
||||||
import {
|
import {
|
||||||
CONTACT_CSV_HEADER,
|
CONTACT_CSV_HEADER,
|
||||||
@@ -416,6 +416,11 @@ export default class ContactsView extends Vue {
|
|||||||
this.apiServer = settings.apiServer || "";
|
this.apiServer = settings.apiServer || "";
|
||||||
this.isRegistered = !!settings.isRegistered;
|
this.isRegistered = !!settings.isRegistered;
|
||||||
|
|
||||||
|
// if these detect a query parameter, they can and then redirect to this URL without a query parameter
|
||||||
|
// to avoid problems when they reload or they go forward & back and it tries to reprocess
|
||||||
|
await this.processContactJwt();
|
||||||
|
await this.processInviteJwt();
|
||||||
|
|
||||||
this.showGiveNumbers = !!settings.showContactGivesInline;
|
this.showGiveNumbers = !!settings.showContactGivesInline;
|
||||||
this.hideRegisterPromptOnNewContact =
|
this.hideRegisterPromptOnNewContact =
|
||||||
!!settings.hideRegisterPromptOnNewContact;
|
!!settings.hideRegisterPromptOnNewContact;
|
||||||
@@ -430,11 +435,13 @@ export default class ContactsView extends Vue {
|
|||||||
this.contacts = baseContacts.sort((a, b) =>
|
this.contacts = baseContacts.sort((a, b) =>
|
||||||
(a.name || "").localeCompare(b.name || ""),
|
(a.name || "").localeCompare(b.name || ""),
|
||||||
);
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
private async processContactJwt() {
|
||||||
// handle a contact sent via URL
|
// handle a contact sent via URL
|
||||||
//
|
//
|
||||||
// Prefer use of /contact-import/:jwt with a JWT that has an array of contacts
|
// For external links, use /contact-import/:jwt with a JWT that has an array of contacts
|
||||||
// unless you want them to import a single contact without confirmation.
|
// because that will do better error checking for things like missing data on iOS platforms.
|
||||||
const importedContactJwt = (this.$route as RouteLocationNormalizedLoaded)
|
const importedContactJwt = (this.$route as RouteLocationNormalizedLoaded)
|
||||||
.query["contactJwt"] as string;
|
.query["contactJwt"] as string;
|
||||||
if (importedContactJwt) {
|
if (importedContactJwt) {
|
||||||
@@ -442,21 +449,25 @@ export default class ContactsView extends Vue {
|
|||||||
const { payload } = decodeEndorserJwt(importedContactJwt);
|
const { payload } = decodeEndorserJwt(importedContactJwt);
|
||||||
const userInfo = payload["own"] as UserInfo;
|
const userInfo = payload["own"] as UserInfo;
|
||||||
const newContact = {
|
const newContact = {
|
||||||
did: payload["iss"],
|
did: userInfo.did || payload["iss"], // ".did" is reliable as of v 0.3.49
|
||||||
name: userInfo.name,
|
name: userInfo.name,
|
||||||
nextPubKeyHashB64: userInfo.nextPublicEncKeyHash,
|
nextPubKeyHashB64: userInfo.nextPublicEncKeyHash,
|
||||||
profileImageUrl: userInfo.profileImageUrl,
|
profileImageUrl: userInfo.profileImageUrl,
|
||||||
publicKeyBase64: userInfo.publicEncKey,
|
publicKeyBase64: userInfo.publicEncKey,
|
||||||
registered: userInfo.registered,
|
registered: userInfo.registered,
|
||||||
} as Contact;
|
} as Contact;
|
||||||
this.addContact(newContact);
|
await this.addContact(newContact);
|
||||||
|
// if we're here, they haven't redirected anywhere, so we'll redirect here without a query parameter
|
||||||
|
(this.$router as Router).push({ path: "/contacts" });
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private async processInviteJwt() {
|
||||||
// handle an invite JWT sent via URL
|
// handle an invite JWT sent via URL
|
||||||
const importedInviteJwt = (this.$route as RouteLocationNormalizedLoaded)
|
const importedInviteJwt = (this.$route as RouteLocationNormalizedLoaded)
|
||||||
.query["inviteJwt"] as string;
|
.query["inviteJwt"] as string;
|
||||||
if (importedInviteJwt === "") {
|
if (importedInviteJwt === "") {
|
||||||
// this happens when a platform (usually iOS) doesn't include anything after the "=" in a shared link.
|
// this happens when a platform (eg iOS) doesn't include anything after the "=" in a shared link.
|
||||||
this.$notify(
|
this.$notify(
|
||||||
{
|
{
|
||||||
group: "alert",
|
group: "alert",
|
||||||
@@ -555,6 +566,8 @@ export default class ContactsView extends Vue {
|
|||||||
5000,
|
5000,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
// if we're here, they haven't redirected anywhere, so we'll redirect here without a query parameter
|
||||||
|
(this.$router as Router).push({ path: "/contacts" });
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -717,12 +730,30 @@ export default class ContactsView extends Vue {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (contactInput.includes(CONTACT_IMPORT_CONFIRM_URL_PATH_TIME_SAFARI)) {
|
||||||
|
const jwt = getContactJwtFromJwtUrl(contactInput);
|
||||||
|
(this.$router as Router).push({
|
||||||
|
path: "/contact-import/" + jwt,
|
||||||
|
});
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (
|
if (
|
||||||
contactInput.includes(CONTACT_IMPORT_CONFIRM_URL_PATH_TIME_SAFARI) ||
|
|
||||||
contactInput.includes(CONTACT_IMPORT_ONE_URL_PATH_TIME_SAFARI) ||
|
contactInput.includes(CONTACT_IMPORT_ONE_URL_PATH_TIME_SAFARI) ||
|
||||||
contactInput.includes(CONTACT_URL_PATH_ENDORSER_CH_OLD)
|
contactInput.includes(CONTACT_URL_PATH_ENDORSER_CH_OLD)
|
||||||
) {
|
) {
|
||||||
await this.addContactFromScan(contactInput);
|
const jwt = getContactJwtFromJwtUrl(contactInput);
|
||||||
|
const { payload } = decodeEndorserJwt(jwt);
|
||||||
|
const userInfo = payload["own"] as UserInfo;
|
||||||
|
const newContact = {
|
||||||
|
did: userInfo.did || payload["iss"], // "did" is reliable as of v 0.3.49
|
||||||
|
name: userInfo.name,
|
||||||
|
nextPubKeyHashB64: userInfo.nextPublicEncKeyHash,
|
||||||
|
profileImageUrl: userInfo.profileImageUrl,
|
||||||
|
publicKeyBase64: userInfo.publicEncKey,
|
||||||
|
registered: userInfo.registered,
|
||||||
|
} as Contact;
|
||||||
|
await this.addContact(newContact);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -870,38 +901,6 @@ export default class ContactsView extends Vue {
|
|||||||
return db.contacts.add(newContact);
|
return db.contacts.add(newContact);
|
||||||
}
|
}
|
||||||
|
|
||||||
private async addContactFromScan(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.",
|
|
||||||
},
|
|
||||||
3000,
|
|
||||||
);
|
|
||||||
return;
|
|
||||||
} else {
|
|
||||||
if (Array.isArray(payload.contacts)) {
|
|
||||||
// reroute to the ContactsImport
|
|
||||||
(this.$router as Router).push({
|
|
||||||
path: "/contact-import/" + url.substring(url.lastIndexOf("/") + 1),
|
|
||||||
});
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
return this.addContact({
|
|
||||||
did: payload.iss,
|
|
||||||
name: payload.own.name,
|
|
||||||
nextPubKeyHashB64: payload.own.nextPublicEncKeyHash,
|
|
||||||
profileImageUrl: payload.own.profileImageUrl,
|
|
||||||
publicKeyBase64: payload.own.publicEncKey,
|
|
||||||
registered: payload.own.registered,
|
|
||||||
} as Contact);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private async addContact(newContact: Contact) {
|
private async addContact(newContact: Contact) {
|
||||||
if (!newContact.did) {
|
if (!newContact.did) {
|
||||||
this.danger("Cannot add a contact without a DID.", "Incomplete Contact");
|
this.danger("Cannot add a contact without a DID.", "Incomplete Contact");
|
||||||
@@ -961,7 +960,7 @@ export default class ContactsView extends Vue {
|
|||||||
},
|
},
|
||||||
-1,
|
-1,
|
||||||
);
|
);
|
||||||
}, 500);
|
}, 1000);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
this.$notify(
|
this.$notify(
|
||||||
|
|||||||
Reference in New Issue
Block a user