<template> <QuickNav selected="Invite" /> <section id="Content" class="p-6 pb-24 max-w-3xl mx-auto"> <div v-if="acceptInput" class="text-center mt-4"> <p>That invitation did not work.</p> <p class="mt-2"> Go back to your invite message and copy the entire text, then paste it here. </p> <p class="mt-2"> If the link looks correct, try Chrome. (For example, iOS may have cut off the invite data, or it may have shown a preview that stole your invite.) If it still complains, you may need the person who invited you to send a new one. </p> <textarea v-model="inputJwt" placeholder="Paste invitation..." class="mt-4 border-2 border-gray-300 p-2 rounded" cols="30" @input="() => checkInvite(inputJwt)" /> <br /> <button @click="() => processInvite(inputJwt, true)" class="ml-2 p-2 bg-blue-500 text-white rounded" > Submit </button> </div> <div v-if="checkingInvite" class="text-lg text-center font-light relative px-7" > <fa icon="spinner" class="fa-spin-pulse" /> Loading… </div> </section> </template> <script lang="ts"> import { Component, Vue } from "vue-facing-decorator"; import { Router } from "vue-router"; import QuickNav from "@/components/QuickNav.vue"; import { NotificationIface } from "@/constants/app"; import { db, logConsoleAndDb, retrieveSettingsForActiveAccount, } from "@/db/index"; import { decodeEndorserJwt } from "@/libs/crypto/vc"; import { errorStringForLog } from "@/libs/endorserServer"; import { generateSaveAndActivateIdentity } from "@/libs/util"; @Component({ components: { QuickNav } }) export default class InviteOneAcceptView extends Vue { $notify!: (notification: NotificationIface, timeout?: number) => void; acceptInput: boolean = false; activeDid: string = ""; apiServer: string = ""; checkingInvite: boolean = true; inputJwt: string = ""; async mounted() { this.checkingInvite = true; await db.open(); const settings = await retrieveSettingsForActiveAccount(); this.activeDid = settings.activeDid || ""; this.apiServer = settings.apiServer || ""; if (!this.activeDid) { this.activeDid = await generateSaveAndActivateIdentity(); } const jwt = window.location.pathname.substring( "/invite-one-accept/".length, ); await this.processInvite(jwt, false); this.checkingInvite = false; } // process the invite JWT and/or text message containing the URL with the JWT async processInvite(jwtInput: string, notifyOnFailure: boolean) { this.checkingInvite = true; try { let jwt: string = jwtInput ?? ""; // parse the string: extract the URL or JWT if surrounded by spaces // and then extract the JWT from the URL const urlMatch = jwtInput.match(/(https?:\/\/[^\s]+)/); if (urlMatch && urlMatch[1]) { // extract the JWT from the URL, meaning any character except "?" const internalMatch = urlMatch[1].match(/\/invite-one-accept\/([^?]+)/); if (internalMatch && internalMatch[1]) { jwt = internalMatch[1]; } } else { // extract the JWT (which starts with "ey") if it is surrounded by other input const spaceMatch = jwtInput.match(/(ey[\w.-]+)/); if (spaceMatch && spaceMatch[1]) { jwt = spaceMatch[1]; } } if (!jwt) { if (notifyOnFailure) { this.$notify( { group: "alert", type: "danger", title: "Missing invite", text: "There was no invite. Paste the entire text that has the link.", }, 5000, ); } this.acceptInput = true; } else { //const payload: JWTPayload = decodeEndorserJwt(jwt); // That's good enough for an initial check. // Send them to the contacts page to finish, with inviteJwt in the query string. (this.$router as Router).push({ name: "contacts", query: { inviteJwt: jwt }, }); } } catch (error) { const fullError = "Error accepting invite: " + errorStringForLog(error); logConsoleAndDb(fullError, true); if (notifyOnFailure) { this.$notify( { group: "alert", type: "danger", title: "Error", text: "There was an error processing that invite.", }, 3000, ); } this.acceptInput = true; } this.checkingInvite = false; } // check the invite JWT async checkInvite(jwtInput: string) { if ( jwtInput.endsWith("invite-one-accept") || jwtInput.endsWith("invite-one-accept/") ) { this.$notify( { group: "alert", type: "danger", title: "Error", text: "That is only part of the invite link; it's missing data at the end. Try another way to get the full link.", }, 5000, ); } } } </script>