Browse Source

change accessToken to take a DID

master
Trent Larson 5 months ago
parent
commit
c67ceebc67
  1. 3
      src/components/PhotoDialog.vue
  2. 17
      src/components/World/components/objects/landmarks.js
  3. 26
      src/libs/crypto/index.ts
  4. 14
      src/libs/endorserServer.ts
  5. 4
      src/libs/util.ts
  6. 6
      src/views/AccountViewView.vue
  7. 7
      src/views/ContactAmountsView.vue
  8. 27
      src/views/DIDView.vue
  9. 30
      src/views/DiscoverView.vue
  10. 3
      src/views/GiftedDetails.vue
  11. 17
      src/views/NewEditProjectView.vue
  12. 61
      src/views/ProjectViewView.vue
  13. 4
      src/views/ProjectsView.vue
  14. 17
      src/views/QuickActionBvcEndView.vue
  15. 3
      src/views/SharedPhotoView.vue

3
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,
};

17
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 });

26
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;
};

14
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);

4
src/libs/util.ts

@ -196,7 +196,9 @@ export function findAllVisibleToDids(
*
**/
export const getAccount = async (activeDid: string): Promise<Account> => {
export const getAccount = async (
activeDid: string,
): Promise<Account | undefined> => {
await accountsDB.open();
const account = (await accountsDB.accounts
.where("did")

6
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/" +

7
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.";

27
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<HeadersInit> {
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),
},
);

30
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<HeadersInit> {
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),
},
);

3
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/" +

17
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,

61
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() {

4
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);
}

17
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 +

3
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,
};

Loading…
Cancel
Save