From f33dee9b7a7ccb9f38c07615442e90b706b585c3 Mon Sep 17 00:00:00 2001 From: Trent Larson Date: Fri, 25 Apr 2025 20:14:30 -0600 Subject: [PATCH 1/4] do not share the invite JWT with the server; always keep it on the client, generated at will --- src/views/InviteOneView.vue | 39 ++++++++++++++++--------------- test-playwright/05-invite.spec.ts | 5 ++++ 2 files changed, 25 insertions(+), 19 deletions(-) diff --git a/src/views/InviteOneView.vue b/src/views/InviteOneView.vue index 563bec4b..f1cbfa36 100644 --- a/src/views/InviteOneView.vue +++ b/src/views/InviteOneView.vue @@ -73,17 +73,15 @@ invite.expiresAt > new Date().toISOString() " class="text-center text-blue-500 cursor-pointer" - :title="inviteLink(invite.jwt)" - @click=" - copyInviteAndNotify(invite.inviteIdentifier, invite.jwt) - " + title="Click to copy invite link" + @click="copyInviteAndNotify(invite)" > {{ getTruncatedInviteId(invite.inviteIdentifier) }} + + @@ -146,7 +146,7 @@ import { logger } from "../utils/logger"; interface Invite { inviteIdentifier: string; expiresAt: string; - jwt: string; + jwt?: string; // only used to store a JWT for testing, after the link is clicked notes: string; redeemedAt: string | null; redeemedBy: string | null; @@ -220,18 +220,27 @@ export default class InviteOneView extends Vue { return `${redeemedBy.slice(0, 13)}...${redeemedBy.slice(-3)}`; } - inviteLink(jwt: string): string { + inviteLink(jwt: string | undefined): string { + if (!jwt) return "Click to set JWT link"; return APP_SERVER + "/invite-one-accept/" + jwt; } - copyInviteAndNotify(inviteId: string, jwt: string) { - useClipboard().copy(this.inviteLink(jwt)); + async copyInviteAndNotify(invite: Invite) { + const expiresIn = (new Date(invite.expiresAt).getTime() - Date.now()) / 1000; + const inviteJwt = await createInviteJwt( + this.activeDid, + undefined, + invite.inviteIdentifier, + expiresIn, + ); + invite.jwt = inviteJwt; // set for testing + useClipboard().copy(this.inviteLink(inviteJwt)); this.$notify( { group: "alert", type: "success", title: "Copied", - text: "Your clipboard now contains the link for invite " + inviteId, + text: "Your clipboard now contains the link for invite " + invite.inviteIdentifier, }, 5000, ); @@ -295,22 +304,14 @@ export default class InviteOneView extends Vue { }, }; } - const expiresIn = (new Date(expiresAt).getTime() - Date.now()) / 1000; - const inviteJwt = await createInviteJwt( - this.activeDid, - undefined, - inviteIdentifier, - expiresIn, - ); await axios.post( this.apiServer + "/api/userUtil/invite", - { inviteJwt: inviteJwt, notes: notes }, + { inviteIdentifier: inviteIdentifier, notes: notes, expiresAt: expiresAt }, { headers }, ); const newInvite = { inviteIdentifier: inviteIdentifier, expiresAt: expiresAt, - jwt: inviteJwt, notes: notes, redeemedAt: null, redeemedBy: null, diff --git a/test-playwright/05-invite.spec.ts b/test-playwright/05-invite.spec.ts index 821f7c39..c0c34668 100644 --- a/test-playwright/05-invite.spec.ts +++ b/test-playwright/05-invite.spec.ts @@ -44,6 +44,11 @@ test('Check User 0 can invite someone', async ({ page }) => { await expect(page.locator('div[role="alert"] button:has-text("Yes")')).toBeHidden(); // check that the invite is in the list + const newInviteRow = page.locator(`tr:has(td:has-text("Neighbor ${neighborNum}"))`); + await expect(newInviteRow).toBeVisible(); + // click on the link in the first column, which generates the JWT in the other column + await newInviteRow.locator('td:first-child').click(); + const newInviteLine = page.locator(`td:has-text("Neighbor ${neighborNum}")`); await expect(newInviteLine).toBeVisible(); // retrieve the link from the title -- 2.30.2 From 4905334ed4e58efca8c785e16d40368502358bc6 Mon Sep 17 00:00:00 2001 From: Trent Larson Date: Mon, 28 Apr 2025 20:16:30 -0600 Subject: [PATCH 2/4] avoid an HTML complaint about bad formatting --- src/views/HelpView.vue | 40 ++++++++++++++++++++-------------------- 1 file changed, 20 insertions(+), 20 deletions(-) diff --git a/src/views/HelpView.vue b/src/views/HelpView.vue index fe4d9555..c7027a86 100644 --- a/src/views/HelpView.vue +++ b/src/views/HelpView.vue @@ -502,27 +502,27 @@ then don't use it.
As for data & privacy: -
    -
  • - If using notifications, a server stores push token data. That can be revoked at any time - by disabling notifications on the Profile page. -
  • -
  • - If sending images, a server stores them, too. They can be removed by editing the claim - and deleting them. -
  • -
  • - If sending other partner system data (eg. to Trustroots) a public key and message - data are stored on a server. Those can be removed via direct personal request. -
  • -
  • - For all other claim data, - - the Endorser Service has this Privacy Policy. - -
  • -

+
    +
  • + If using notifications, a server stores push token data. That can be revoked at any time + by disabling notifications on the Profile page. +
  • +
  • + If sending images, a server stores them, too. They can be removed by editing the claim + and deleting them. +
  • +
  • + If sending other partner system data (eg. to Trustroots) a public key and message + data are stored on a server. Those can be removed via direct personal request. +
  • +
  • + For all other claim data, + + the Endorser Service has this Privacy Policy. + +
  • +

How can I contribute?

-- 2.30.2 From ba9bb8a26ebf00089ff040447df37c766b5d80ee Mon Sep 17 00:00:00 2001 From: Trent Larson Date: Tue, 29 Apr 2025 20:39:45 -0600 Subject: [PATCH 3/4] rework contacts screen to show activity buttons always but totals on request --- src/views/ContactsView.vue | 211 +++++++++++++++++++------------------ 1 file changed, 106 insertions(+), 105 deletions(-) diff --git a/src/views/ContactsView.vue b/src/views/ContactsView.vue index c59e13ee..3ecbd593 100644 --- a/src/views/ContactsView.vue +++ b/src/views/ContactsView.vue @@ -92,7 +92,7 @@

-
+
-
-
-
- In the following, only the most recent hours are included. To see more, - click - - +
+ + Only the most recent From/To hours show in buttons. To see more, + click + + +
- + + +
@@ -179,79 +178,82 @@ class="border-b border-slate-300 pt-1 pb-1" data-testId="contactListItem" > -
-
- - - - -

- {{ contactNameNonBreakingSpace(contact.name) }} -

- - -
- - - - - {{ - libsUtil.shortDid(contact.did) - }} -
-
- {{ contact.notes }} -
+
+ + + + + + +

+ {{ contactNameNonBreakingSpace(contact.name) }} +

+ + +
+ + + + + {{ + libsUtil.shortDid(contact.did) + }} +
+
+ {{ contact.notes }} +
+
-
-
+
+
@@ -299,7 +303,6 @@