From cd9f0971805735fbfbfc997637569184293bd5b4 Mon Sep 17 00:00:00 2001 From: Trent Larson Date: Sat, 5 Oct 2024 18:35:59 -0600 Subject: [PATCH] add page for one-on-one invites (incomplete) --- src/components/InviteDialog.vue | 118 ++++++++++++++++++ src/components/UserNameDialog.vue | 2 +- src/libs/crypto/vc/index.ts | 10 +- src/libs/endorserServer.ts | 35 ++++-- src/main.ts | 2 + src/router/index.ts | 5 + src/views/ContactsView.vue | 45 ++++--- src/views/InviteOneView.vue | 195 ++++++++++++++++++++++++++++++ src/views/NewEditProjectView.vue | 10 +- 9 files changed, 390 insertions(+), 32 deletions(-) create mode 100644 src/components/InviteDialog.vue create mode 100644 src/views/InviteOneView.vue diff --git a/src/components/InviteDialog.vue b/src/components/InviteDialog.vue new file mode 100644 index 000000000..b514608bf --- /dev/null +++ b/src/components/InviteDialog.vue @@ -0,0 +1,118 @@ + + + + + diff --git a/src/components/UserNameDialog.vue b/src/components/UserNameDialog.vue index bd412ae2d..50747860c 100644 --- a/src/components/UserNameDialog.vue +++ b/src/components/UserNameDialog.vue @@ -46,7 +46,7 @@ import { MASTER_SETTINGS_KEY } from "@/db/tables/settings"; export default class UserNameDialog extends Vue { $notify!: (notification: NotificationIface, timeout?: number) => void; - callback: (string?) => void = () => {}; + callback: (name?: string) => void = () => {}; givenName = ""; visible = false; diff --git a/src/libs/crypto/vc/index.ts b/src/libs/crypto/vc/index.ts index bc1caabf6..677b4a88b 100644 --- a/src/libs/crypto/vc/index.ts +++ b/src/libs/crypto/vc/index.ts @@ -54,16 +54,22 @@ export function isFromPasskey(keyMeta?: KeyMeta): boolean { export async function createEndorserJwtForKey( account: KeyMeta, payload: object, + expiresIn?: number, ) { if (account?.identity) { // eslint-disable-next-line @typescript-eslint/no-non-null-assertion const identity: IIdentifier = JSON.parse(account.identity!); const privateKeyHex = identity.keys[0].privateKeyHex; const signer = await SimpleSigner(privateKeyHex as string); - return didJwt.createJWT(payload, { + const options = { issuer: account.did, signer: signer, - }); + expiresIn: undefined as number | undefined, + } + if (expiresIn) { + options.expiresIn = expiresIn; + } + return didJwt.createJWT(payload, options); } else if (account?.passkeyCredIdHex) { return createDidPeerJwt(account.did, account.passkeyCredIdHex, payload); } else { diff --git a/src/libs/endorserServer.ts b/src/libs/endorserServer.ts index f6887383f..ae6484e45 100644 --- a/src/libs/endorserServer.ts +++ b/src/libs/endorserServer.ts @@ -239,8 +239,9 @@ export interface RegisterVerifiableCredential { "@context": string; "@type": string; agent: { identifier: string }; + identifier?: string; object: string; - participant: { identifier: string }; + participant?: { identifier: string }; } // now for some of the error & other wrapper types @@ -993,9 +994,10 @@ export async function generateEndorserJwtForAccount( export async function createEndorserJwtForDid( issuerDid: string, payload: object, + expiresIn?: number, ) { const account = await getAccount(issuerDid); - return createEndorserJwtForKey(account as KeyMeta, payload); + return createEndorserJwtForKey(account as KeyMeta, payload, expiresIn); } /** @@ -1225,19 +1227,24 @@ export async function createEndorserJwtVcFromClaim( return createEndorserJwtForDid(issuerDid, vcPayload); } -export async function register( +export async function createInviteJwt( activeDid: string, - apiServer: string, - axios: Axios, - contact: Contact, -) { + contact?: Contact, + inviteId?: string, + expiresIn?: number, +): Promise { const vcClaim: RegisterVerifiableCredential = { "@context": SCHEMA_ORG_CONTEXT, "@type": "RegisterAction", agent: { identifier: activeDid }, object: SERVICE_ID, - participant: { identifier: contact.did }, }; + if (contact) { + vcClaim.participant = { identifier: contact.did }; + } + if (inviteId) { + vcClaim.identifier = inviteId; + } // Make a payload for the claim const vcPayload = { vc: { @@ -1247,7 +1254,17 @@ export async function register( }, }; // Create a signature using private key of identity - const vcJwt = await createEndorserJwtForDid(activeDid, vcPayload); + const vcJwt = await createEndorserJwtForDid(activeDid, vcPayload, expiresIn); + return vcJwt; +} + +export async function register( + activeDid: string, + apiServer: string, + axios: Axios, + contact: Contact, +): Promise<{ success?: boolean; error?: string }> { + const vcJwt = await createInviteJwt(activeDid, contact); const url = apiServer + "/api/v2/claim"; const resp = await axios.post(url, { jwtEncoded: vcJwt }); diff --git a/src/main.ts b/src/main.ts index 595a80cdd..46e9e7029 100644 --- a/src/main.ts +++ b/src/main.ts @@ -39,6 +39,7 @@ import { faDollar, faEllipsis, faEllipsisVertical, + faEnvelopeOpenText, faEye, faEyeSlash, faFileLines, @@ -109,6 +110,7 @@ library.add( faDollar, faEllipsis, faEllipsisVertical, + faEnvelopeOpenText, faEye, faEyeSlash, faFileLines, diff --git a/src/router/index.ts b/src/router/index.ts index b19aa51b2..3ceda6a6d 100644 --- a/src/router/index.ts +++ b/src/router/index.ts @@ -128,6 +128,11 @@ const routes: Array = [ name: "import-derive", component: () => import("../views/ImportDerivedAccountView.vue"), }, + { + path: "/invite-one", + name: "invite-one", + component: () => import("../views/InviteOneView.vue"), + }, { path: "/new-edit-account", name: "new-edit-account", diff --git a/src/views/ContactsView.vue b/src/views/ContactsView.vue index 7dc9dc388..b62d9b9f6 100644 --- a/src/views/ContactsView.vue +++ b/src/views/ContactsView.vue @@ -23,12 +23,20 @@
+ + + + +