11 changed files with 220 additions and 64 deletions
			
			
		@ -1,3 +1,5 @@ | 
				
			|||
 | 
				
			|||
# I tried and failed to set things here with vue-cli-service but | 
				
			|||
# things may be more reliable with vite so let's try again. | 
				
			|||
 | 
				
			|||
VITE_APP_SERVER=http://localhost:8080 | 
				
			|||
 | 
				
			|||
@ -0,0 +1,138 @@ | 
				
			|||
<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> | 
				
			|||
      <input | 
				
			|||
        v-model="inputJwt" | 
				
			|||
        type="text" | 
				
			|||
        placeholder="Paste invitation..." | 
				
			|||
        class="mt-4 border-2 border-gray-300 p-2 rounded" | 
				
			|||
      /> | 
				
			|||
      <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, retrieveSettingsForActiveAccount } from "@/db/index"; | 
				
			|||
import { decodeEndorserJwt } from "@/libs/crypto/vc"; | 
				
			|||
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) { | 
				
			|||
      console.error("Error accepting invite:", error); | 
				
			|||
      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; | 
				
			|||
  } | 
				
			|||
} | 
				
			|||
</script> | 
				
			|||
					Loading…
					
					
				
		Reference in new issue