From c67ceebc67c1d6bc6f04bc72eea4ff4ac68d0427 Mon Sep 17 00:00:00 2001 From: Trent Larson Date: Tue, 9 Jul 2024 19:20:05 -0600 Subject: [PATCH] change accessToken to take a DID --- src/components/PhotoDialog.vue | 3 +- .../World/components/objects/landmarks.js | 17 +----- src/libs/crypto/index.ts | 26 +------- src/libs/endorserServer.ts | 14 ++--- src/libs/util.ts | 4 +- src/views/AccountViewView.vue | 6 +- src/views/ContactAmountsView.vue | 7 ++- src/views/DIDView.vue | 27 +------- src/views/DiscoverView.vue | 30 +-------- src/views/GiftedDetails.vue | 3 +- src/views/NewEditProjectView.vue | 17 ++---- src/views/ProjectViewView.vue | 61 ++++--------------- src/views/ProjectsView.vue | 4 +- src/views/QuickActionBvcEndView.vue | 17 +----- src/views/SharedPhotoView.vue | 3 +- 15 files changed, 47 insertions(+), 192 deletions(-) diff --git a/src/components/PhotoDialog.vue b/src/components/PhotoDialog.vue index b28f82d..ce5aaaf 100644 --- a/src/components/PhotoDialog.vue +++ b/src/components/PhotoDialog.vue @@ -348,8 +348,7 @@ export default class PhotoDialog extends Vue { this.blob = (await cropper?.getBlob()) || undefined; } - const identifier = await getIdentity(this.activeDid); - const token = await accessToken(identifier); + const token = await accessToken(this.activeDid); const headers = { Authorization: "Bearer " + token, }; diff --git a/src/components/World/components/objects/landmarks.js b/src/components/World/components/objects/landmarks.js index b8163a2..eb0f8f9 100644 --- a/src/components/World/components/objects/landmarks.js +++ b/src/components/World/components/objects/landmarks.js @@ -1,12 +1,11 @@ import axios from "axios"; -import * as R from "ramda"; import * as THREE from "three"; import { GLTFLoader } from "three/addons/loaders/GLTFLoader"; import * as SkeletonUtils from "three/addons/utils/SkeletonUtils"; import * as TWEEN from "@tweenjs/tween.js"; -import { accountsDB, db } from "@/db"; +import { db } from "@/db"; import { MASTER_SETTINGS_KEY } from "@/db/tables/settings"; -import { accessToken } from "@/libs/crypto"; +import { getHeaders } from "@/libs/endorserServer"; const ANIMATION_DURATION_SECS = 10; const ENDORSER_ENTITY_PREFIX = "https://endorser.ch/entity/"; @@ -19,17 +18,7 @@ export async function loadLandmarks(vue, world, scene, loop) { const settings = await db.settings.get(MASTER_SETTINGS_KEY); const activeDid = settings?.activeDid || ""; const apiServer = settings?.apiServer; - await accountsDB.open(); - const accounts = await accountsDB.accounts.toArray(); - const account = R.find((acc) => acc.did === activeDid, accounts); - const headers = { - "Content-Type": "application/json", - }; - const identity = JSON.parse(account?.identity || "null"); - if (identity) { - const token = await accessToken(identity); - headers["Authorization"] = "Bearer " + token; - } + const headers = await getHeaders(activeDid); const url = apiServer + "/api/v2/report/claims?claimType=GiveAction"; const resp = await axios.get(url, { headers: headers }); diff --git a/src/libs/crypto/index.ts b/src/libs/crypto/index.ts index ee63012..d89508e 100644 --- a/src/libs/crypto/index.ts +++ b/src/libs/crypto/index.ts @@ -86,43 +86,21 @@ export const generateSeed = (): string => { /** * Retreive an access token * - * @param {IIdentifier} identifier * @return {*} */ -export const accessToken = async ( - identifier: IIdentifier | undefined, - did?: string, -) => { +export const accessToken = async (did?: string) => { if (did) { const nowEpoch = Math.floor(Date.now() / 1000); const endEpoch = nowEpoch + 60; // add one minute const tokenPayload = { exp: endEpoch, iat: nowEpoch, iss: did }; return createEndorserJwt(did, tokenPayload); } else { - // deprecated - // must have identifier - const did = identifier?.did; - const privateKeyHex: string = identifier?.keys[0].privateKeyHex as string; - - const signer = SimpleSigner(privateKeyHex); - - const nowEpoch = Math.floor(Date.now() / 1000); - const endEpoch = nowEpoch + 60; // add one minute - - const tokenPayload = { exp: endEpoch, iat: nowEpoch, iss: did }; - const alg = undefined; // defaults to 'ES256K', more standardized but harder to verify vs ES256K-R - const jwt: string = await didJwt.createJWT(tokenPayload, { - alg, - issuer: did || "no DID set", - signer, - }); - return jwt; + return null; } }; export const sign = async (privateKeyHex: string) => { const signer = SimpleSigner(privateKeyHex); - return signer; }; diff --git a/src/libs/endorserServer.ts b/src/libs/endorserServer.ts index e4894ac..b124ca5 100644 --- a/src/libs/endorserServer.ts +++ b/src/libs/endorserServer.ts @@ -1,8 +1,4 @@ -import { - Axios, - AxiosRequestConfig, - AxiosResponse, -} from "axios"; +import { Axios, AxiosRequestConfig, AxiosResponse } from "axios"; import * as didJwt from "did-jwt"; import { LRUCache } from "lru-cache"; import * as R from "ramda"; @@ -458,7 +454,7 @@ export async function getHeaders(did?: string) { "Content-Type": "application/json", }; if (did) { - const token = await accessToken(undefined, did); + const token = await accessToken(did); headers["Authorization"] = "Bearer " + token; } else { // it's often OK to request without auth; we assume necessary checks are done earlier @@ -716,7 +712,7 @@ export async function createAndSubmitClaim( // Make the xhr request payload const payload = JSON.stringify({ jwtEncoded: vcJwt }); const url = `${apiServer}/api/v2/claim`; - const token = await accessToken(identity); + const token = await accessToken(identity.did); const response = await axios.post(url, payload, { headers: { @@ -948,7 +944,7 @@ export const bvcMeetingJoinClaim = (did: string, startTime: string) => { export async function createEndorserJwt(did: string, payload: object) { const account = await getAccount(did); - if (account.identity) { + if (account?.identity) { // eslint-disable-next-line @typescript-eslint/no-non-null-assertion const identity = JSON.parse(account.identity!); const privateKeyHex = identity.keys[0].privateKeyHex; @@ -957,7 +953,7 @@ export async function createEndorserJwt(did: string, payload: object) { issuer: did, signer: signer, }); - } else if (account.passkeyCredIdHex) { + } else if (account?.passkeyCredIdHex) { return createDidPeerJwt(did, account.passkeyCredIdHex, payload); } else { throw new Error("No identity data found to sign for DID " + did); diff --git a/src/libs/util.ts b/src/libs/util.ts index 54dd626..2e9c980 100644 --- a/src/libs/util.ts +++ b/src/libs/util.ts @@ -196,7 +196,9 @@ export function findAllVisibleToDids( * **/ -export const getAccount = async (activeDid: string): Promise => { +export const getAccount = async ( + activeDid: string, +): Promise => { await accountsDB.open(); const account = (await accountsDB.accounts .where("did") diff --git a/src/views/AccountViewView.vue b/src/views/AccountViewView.vue index 60e046f..0e4034b 100644 --- a/src/views/AccountViewView.vue +++ b/src/views/AccountViewView.vue @@ -1432,11 +1432,7 @@ export default class AccountViewView extends Vue { return; } try { - const identity = await this.getIdentity(this.activeDid); - if (!identity) { - throw Error("No identity found."); - } - const token = await accessToken(identity); + const token = await accessToken(this.activeDid); const response = await this.axios.delete( DEFAULT_IMAGE_API_SERVER + "/image/" + diff --git a/src/views/ContactAmountsView.vue b/src/views/ContactAmountsView.vue index f4ff1fb..3749dd4 100644 --- a/src/views/ContactAmountsView.vue +++ b/src/views/ContactAmountsView.vue @@ -282,7 +282,7 @@ export default class ContactAmountssView extends Vue { }; // Make a payload for the claim - const vcPayload = { + const vcPayload: didJwt.JWTPayload = { vc: { "@context": ["https://www.w3.org/2018/credentials/v1"], type: ["VerifiableCredential"], @@ -307,7 +307,7 @@ export default class ContactAmountssView extends Vue { // Make the xhr request payload const payload = JSON.stringify({ jwtEncoded: vcJwt }); const url = this.apiServer + "/api/v2/claim"; - const token = await accessToken(identity); + const token = await accessToken(this.activeDid); const headers = { "Content-Type": "application/json", Authorization: "Bearer " + token, @@ -316,7 +316,8 @@ export default class ContactAmountssView extends Vue { try { const resp = await this.axios.post(url, payload, { headers }); if (resp.data?.success) { - record.amountConfirmed = origClaim.object?.amountOfThisGood || 1; + record.amountConfirmed = + (origClaim.object?.amountOfThisGood as number) || 1; } } catch (error) { let userMessage = "There was an error. See logs for more info."; diff --git a/src/views/DIDView.vue b/src/views/DIDView.vue index 3183b7d..ea1d93d 100644 --- a/src/views/DIDView.vue +++ b/src/views/DIDView.vue @@ -141,6 +141,7 @@ import { capitalizeAndInsertSpacesBeforeCaps, didInfoForContact, displayAmount, + getHeaders, GenericCredWrapper, GenericVerifiableCredential, GiveVerifiableCredential, @@ -203,30 +204,6 @@ export default class DIDView extends Vue { this.allMyDids = allAccounts.map((acc) => acc.did); } - public async buildHeaders(): Promise { - const headers: HeadersInit = { - "Content-Type": "application/json", - }; - - if (this.activeDid) { - await accountsDB.open(); - const allAccounts = await accountsDB.accounts.toArray(); - const account = allAccounts.find((acc) => acc.did === this.activeDid); - const identity = JSON.parse((account?.identity as string) || "null"); - - if (!identity) { - throw new Error( - "An ID is chosen but there are no keys for it so it cannot be used to talk with the service. Switch your ID.", - ); - } - - headers["Authorization"] = "Bearer " + (await accessToken(identity)); - } else { - // it's OK without auth... we just won't get any identifiers - } - return headers; - } - /** * Data loader used by infinite scroller * @param payload is the flag from the InfiniteScroll indicating if it should load @@ -255,7 +232,7 @@ export default class DIDView extends Vue { this.apiServer + "/api/v2/report/claims?" + queryParams + postfix, { method: "GET", - headers: await this.buildHeaders(), + headers: await getHeaders(this.activeDid), }, ); diff --git a/src/views/DiscoverView.vue b/src/views/DiscoverView.vue index 62635fc..b135649 100644 --- a/src/views/DiscoverView.vue +++ b/src/views/DiscoverView.vue @@ -139,7 +139,7 @@ import { accountsDB, db } from "@/db/index"; import { Contact } from "@/db/tables/contacts"; import { BoundingBox, MASTER_SETTINGS_KEY } from "@/db/tables/settings"; import { accessToken } from "@/libs/crypto"; -import { didInfo, PlanData } from "@/libs/endorserServer"; +import { didInfo, getHeaders, PlanData } from "@/libs/endorserServer"; @Component({ components: { @@ -203,30 +203,6 @@ export default class DiscoverView extends Vue { } } - public async buildHeaders(): Promise { - const headers: HeadersInit = { - "Content-Type": "application/json", - }; - - if (this.activeDid) { - await accountsDB.open(); - const allAccounts = await accountsDB.accounts.toArray(); - const account = allAccounts.find((acc) => acc.did === this.activeDid); - const identity = JSON.parse(account?.identity || "null"); - - if (!identity) { - throw new Error( - "An ID is chosen but there are no keys for it so it cannot be used to talk with the service. Switch your ID.", - ); - } - - headers["Authorization"] = "Bearer " + (await accessToken(identity)); - } else { - // it's OK without auth... we just won't get any identifiers - } - return headers; - } - public async searchAll(beforeId?: string) { this.resetCounts(); @@ -247,7 +223,7 @@ export default class DiscoverView extends Vue { this.apiServer + "/api/v2/report/plans?" + queryParams, { method: "GET", - headers: await this.buildHeaders(), + headers: await getHeaders(this.activeDid) }, ); @@ -337,7 +313,7 @@ export default class DiscoverView extends Vue { this.apiServer + "/api/v2/report/plansByLocation?" + queryParams, { method: "GET", - headers: await this.buildHeaders(), + headers: await getHeaders(this.activeDid), }, ); diff --git a/src/views/GiftedDetails.vue b/src/views/GiftedDetails.vue index 4e06d16..bd9397c 100644 --- a/src/views/GiftedDetails.vue +++ b/src/views/GiftedDetails.vue @@ -381,8 +381,7 @@ export default class GiftedDetails extends Vue { return; } try { - const identity = await libsUtil.getIdentity(this.activeDid); - const token = await accessToken(identity); + const token = await accessToken(this.activeDid); const response = await this.axios.delete( DEFAULT_IMAGE_API_SERVER + "/image/" + diff --git a/src/views/NewEditProjectView.vue b/src/views/NewEditProjectView.vue index b84947c..b48e31c 100644 --- a/src/views/NewEditProjectView.vue +++ b/src/views/NewEditProjectView.vue @@ -258,23 +258,17 @@ export default class NewEditProjectView extends Vue { if (this.numAccounts === 0) { this.errNote("There was a problem loading your account info."); } else { - const identity = await this.getIdentity(this.activeDid); - if (!identity) { - throw new Error( - "An ID is chosen but there are no keys for it so it cannot be used to talk with the service. Switch your ID.", - ); - } - this.loadProject(identity); + this.loadProject(this.activeDid); } } } - async loadProject(identity: IIdentifier) { + async loadProject(userDid: string) { const url = this.apiServer + "/api/claim/byHandle/" + encodeURIComponent(this.projectId); - const token = await accessToken(identity); + const token = await accessToken(userDid); const headers = { "Content-Type": "application/json", Authorization: "Bearer " + token, @@ -333,8 +327,7 @@ export default class NewEditProjectView extends Vue { return; } try { - const identity = await libsUtil.getIdentity(this.activeDid); - const token = await accessToken(identity); + const token = await accessToken(this.activeDid); const response = await this.axios.delete( DEFAULT_IMAGE_API_SERVER + "/image/" + @@ -464,7 +457,7 @@ export default class NewEditProjectView extends Vue { const payload = JSON.stringify({ jwtEncoded: vcJwt }); const url = this.apiServer + "/api/v2/claim"; - const token = await accessToken(identity); + const token = await accessToken(identity.did); const headers = { "Content-Type": "application/json", Authorization: "Bearer " + token, diff --git a/src/views/ProjectViewView.vue b/src/views/ProjectViewView.vue index 259bd1f..4202c94 100644 --- a/src/views/ProjectViewView.vue +++ b/src/views/ProjectViewView.vue @@ -422,6 +422,7 @@ import * as libsUtil from "@/libs/util"; import { BLANK_GENERIC_SERVER_RECORD, GenericCredWrapper, + getHeaders, GiverReceiverInputInfo, GiveSummaryRecord, OfferSummaryRecord, @@ -484,14 +485,12 @@ export default class ProjectViewView extends Vue { const accounts = accountsDB.accounts; const accountsArr: Account[] = await accounts?.toArray(); this.allMyDids = accountsArr.map((acc) => acc.did); - const account = accountsArr.find((acc) => acc.did === this.activeDid); - const identity = JSON.parse((account?.identity as string) || "null"); const pathParam = window.location.pathname.substring("/project/".length); if (pathParam) { this.projectId = decodeURIComponent(pathParam); } - this.loadProject(this.projectId, identity); + this.loadProject(this.projectId, this.activeDid); } public async getIdentity(activeDid: string) { @@ -521,18 +520,12 @@ export default class ProjectViewView extends Vue { this.expanded = false; } - async loadProject(projectId: string, identity: IIdentifier) { + async loadProject(projectId: string, userDid: string) { this.projectId = projectId; const url = this.apiServer + "/api/claim/byHandle/" + encodeURIComponent(projectId); - const headers: RawAxiosRequestHeaders = { - "Content-Type": "application/json", - }; - if (identity) { - const token = await accessToken(identity); - headers["Authorization"] = "Bearer " + token; - } + const headers = await getHeaders(userDid); try { const resp = await this.axios.get(url, { headers }); @@ -602,8 +595,8 @@ export default class ProjectViewView extends Vue { this.loadPlanFulfillersTo(); // now load fulfilled-by, a single project - if (identity) { - const token = await accessToken(identity); + if (this.activeDid) { + const token = await accessToken(this.activeDid); headers["Authorization"] = "Bearer " + token; } const fulfilledByUrl = @@ -655,15 +648,7 @@ export default class ProjectViewView extends Vue { } const givesInUrl = givesUrl + postfix; - const headers: RawAxiosRequestHeaders = { - "Content-Type": "application/json", - }; - const identity = await this.getIdentity(this.activeDid); - if (identity) { - const token = await accessToken(identity); - headers["Authorization"] = "Bearer " + token; - } - + const headers = await getHeaders(this.activeDid); try { const resp = await this.axios.get(givesInUrl, { headers }); if (resp.status === 200 && resp.data.data) { @@ -710,15 +695,7 @@ export default class ProjectViewView extends Vue { } const offersInUrl = offersUrl + postfix; - const headers: RawAxiosRequestHeaders = { - "Content-Type": "application/json", - }; - const identity = await this.getIdentity(this.activeDid); - if (identity) { - const token = await accessToken(identity); - headers["Authorization"] = "Bearer " + token; - } - + const headers = await getHeaders(this.activeDid); try { const resp = await this.axios.get(offersInUrl, { headers }); if (resp.status === 200 && resp.data.data) { @@ -766,15 +743,7 @@ export default class ProjectViewView extends Vue { } const fulfillsInUrl = fulfillsUrl + postfix; - const headers: RawAxiosRequestHeaders = { - "Content-Type": "application/json", - }; - const identity = await this.getIdentity(this.activeDid); - if (identity) { - const token = await accessToken(identity); - headers["Authorization"] = "Bearer " + token; - } - + const headers = await getHeaders(this.activeDid); try { const resp = await this.axios.get(fulfillsInUrl, { headers }); if (resp.status === 200) { @@ -822,15 +791,7 @@ export default class ProjectViewView extends Vue { } const providedByFullUrl = providedByUrl + postfix; - const headers: RawAxiosRequestHeaders = { - "Content-Type": "application/json", - }; - const identity = await this.getIdentity(this.activeDid); - if (identity) { - const token = await accessToken(identity); - headers["Authorization"] = "Bearer " + token; - } - + const headers = await getHeaders(this.activeDid); try { const resp = await this.axios.get(providedByFullUrl, { headers }); if (resp.status === 200) { @@ -877,7 +838,7 @@ export default class ProjectViewView extends Vue { path: "/project/" + encodeURIComponent(projectId), }; this.$router.push(route); - this.loadProject(projectId, await this.getIdentity(this.activeDid)); + this.loadProject(projectId, this.activeDid); } getOpenStreetMapUrl() { diff --git a/src/views/ProjectsView.vue b/src/views/ProjectsView.vue index d4c003c..198b3e8 100644 --- a/src/views/ProjectsView.vue +++ b/src/views/ProjectsView.vue @@ -356,7 +356,7 @@ export default class ProjectsView extends Vue { async loadProjects(identifier?: IIdentifier, urlExtra: string = "") { const identity = identifier || this.currentIid; const url = `${this.apiServer}/api/v2/report/plansByIssuer?${urlExtra}`; - const token: string = await accessToken(identity); + const token: string = await accessToken(identity.did); await this.projectDataLoader(url, token); } @@ -474,7 +474,7 @@ export default class ProjectsView extends Vue { async loadOffers(identifier?: IIdentifier, urlExtra: string = "") { const identity = identifier || this.currentIid; const url = `${this.apiServer}/api/v2/report/offers?offeredByDid=${identity.did}${urlExtra}`; - const token: string = await accessToken(identity); + const token: string = await accessToken(identity.did); await this.offerDataLoader(url, token); } diff --git a/src/views/QuickActionBvcEndView.vue b/src/views/QuickActionBvcEndView.vue index 741dcb6..c671108 100644 --- a/src/views/QuickActionBvcEndView.vue +++ b/src/views/QuickActionBvcEndView.vue @@ -138,26 +138,24 @@ import axios from "axios"; import { DateTime } from "luxon"; import * as R from "ramda"; -import { IIdentifier } from "@veramo/core"; import { Component, Vue } from "vue-facing-decorator"; import QuickNav from "@/components/QuickNav.vue"; import TopMessage from "@/components/TopMessage.vue"; import { NotificationIface } from "@/constants/app"; import { accountsDB, db } from "@/db/index"; -import { Account } from "@/db/tables/accounts"; import { Contact } from "@/db/tables/contacts"; import { MASTER_SETTINGS_KEY, Settings } from "@/db/tables/settings"; -import { accessToken } from "@/libs/crypto"; import { BVC_MEETUPS_PROJECT_CLAIM_ID, claimSpecialDescription, containsHiddenDid, createAndSubmitConfirmation, createAndSubmitGive, - ErrorResult, GenericCredWrapper, GenericVerifiableCredential, + getHeaders, + ErrorResult, } from "@/libs/endorserServer"; import * as libsUtil from "@/libs/util"; @@ -213,16 +211,7 @@ export default class QuickActionBvcBeginView extends Vue { await accountsDB.open(); const allAccounts = await accountsDB.accounts.toArray(); this.allMyDids = allAccounts.map((acc) => acc.did); - const account: Account | undefined = await accountsDB.accounts - .where("did") - .equals(this.activeDid) - .first(); - const identity: IIdentifier = JSON.parse( - (account?.identity as string) || "null", - ); - const headers = { - Authorization: "Bearer " + (await accessToken(identity)), - }; + const headers = await getHeaders(this.activeDid); try { const response = await fetch( this.apiServer + diff --git a/src/views/SharedPhotoView.vue b/src/views/SharedPhotoView.vue index 5f5135c..763c0a6 100644 --- a/src/views/SharedPhotoView.vue +++ b/src/views/SharedPhotoView.vue @@ -152,8 +152,7 @@ export default class SharedPhotoView extends Vue { let result; try { // send the image to the server - const identifier = await getIdentity(this.activeDid as string); - const token = await accessToken(identifier); + const token = await accessToken(this.activeDid); const headers = { Authorization: "Bearer " + token, };