Trent Larson
1 month ago
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 |
# 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. |
# 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