Browse Source

replace remaining didJwt.createJwt calls with one that checks for did:peer

pull/119/head
Trent Larson 2 months ago
parent
commit
674ca1d63c
  1. 3
      src/components/GiftedDialog.vue
  2. 3
      src/components/OfferDialog.vue
  3. 5
      src/libs/crypto/index.ts
  4. 82
      src/libs/endorserServer.ts
  5. 2
      src/libs/util.ts
  6. 3
      src/test/index.ts
  7. 89
      src/views/AccountViewView.vue
  8. 2
      src/views/ClaimAddRawView.vue
  9. 2
      src/views/ClaimView.vue
  10. 2
      src/views/ConfirmGiftView.vue
  11. 97
      src/views/ContactAmountsView.vue
  12. 12
      src/views/ContactQRScanShowView.vue
  13. 18
      src/views/ContactsView.vue
  14. 3
      src/views/GiftedDetails.vue
  15. 157
      src/views/NewEditProjectView.vue
  16. 2
      src/views/ProjectViewView.vue
  17. 5
      src/views/QuickActionBvcBeginView.vue
  18. 8
      src/views/QuickActionBvcEndView.vue

3
src/components/GiftedDialog.vue

@ -287,11 +287,10 @@ export default class GiftedDialog extends Vue {
unitCode: string = "HUR",
) {
try {
const identity = await libsUtil.getIdentity(this.activeDid);
const result = await createAndSubmitGive(
this.axios,
this.apiServer,
identity,
this.activeDid,
giverDid,
this.receiver?.did as string,
description,

3
src/components/OfferDialog.vue

@ -223,11 +223,10 @@ export default class OfferDialog extends Vue {
}
try {
const identity = await libsUtil.getIdentity(this.activeDid);
const result = await createAndSubmitOffer(
this.axios,
this.apiServer,
identity,
this.activeDid,
description,
amount,
unitCode,

5
src/libs/crypto/index.ts

@ -101,11 +101,6 @@ export const accessToken = async (did?: string) => {
}
};
export const sign = async (privateKeyHex: string) => {
const signer = SimpleSigner(privateKeyHex);
return signer;
};
/**
* Copied out of did-jwt since it's deprecated in that library.
*

82
src/libs/endorserServer.ts

@ -2,7 +2,6 @@ import { Axios, AxiosRequestConfig, AxiosResponse } from "axios";
import * as didJwt from "did-jwt";
import { LRUCache } from "lru-cache";
import * as R from "ramda";
import { IIdentifier } from "@veramo/core";
import { DEFAULT_IMAGE_API_SERVER } from "@/constants/app";
import { Contact } from "@/db/tables/contacts";
@ -516,6 +515,9 @@ export async function setPlanInCache(
planCache.set(handleId, planSummary);
}
/**
* Construct GiveAction VC for submission to server
*/
export function constructGive(
fromDid?: string | null,
toDid?: string,
@ -570,7 +572,7 @@ export function constructGive(
export async function createAndSubmitGive(
axios: Axios,
apiServer: string,
identity: IIdentifier,
issuerDid: string,
fromDid?: string | null,
toDid?: string,
description?: string,
@ -594,7 +596,7 @@ export async function createAndSubmitGive(
);
return createAndSubmitClaim(
vcClaim as GenericCredWrapper,
identity,
issuerDid,
apiServer,
axios,
);
@ -612,7 +614,7 @@ export async function createAndSubmitGive(
export async function createAndSubmitOffer(
axios: Axios,
apiServer: string,
identity: IIdentifier,
issuerDid: string,
description?: string,
amount?: number,
unitCode?: string,
@ -623,7 +625,7 @@ export async function createAndSubmitOffer(
const vcClaim: OfferVerifiableCredential = {
"@context": SCHEMA_ORG_CONTEXT,
"@type": "Offer",
offeredBy: { identifier: identity.did },
offeredBy: { identifier: issuerDid },
validThrough: expirationDate || undefined,
};
if (amount) {
@ -647,7 +649,7 @@ export async function createAndSubmitOffer(
}
return createAndSubmitClaim(
vcClaim as GenericCredWrapper,
identity,
issuerDid,
apiServer,
axios,
);
@ -655,7 +657,7 @@ export async function createAndSubmitOffer(
// similar logic is found in endorser-mobile
export const createAndSubmitConfirmation = async (
identifier: IIdentifier,
issuerDid: string,
claim: GenericVerifiableCredential,
lastClaimId: string, // used to set the lastClaimId
handleId: string | undefined,
@ -672,12 +674,12 @@ export const createAndSubmitConfirmation = async (
"@type": "AgreeAction",
object: goodClaim,
};
return createAndSubmitClaim(confirmationClaim, identifier, apiServer, axios);
return createAndSubmitClaim(confirmationClaim, issuerDid, apiServer, axios);
};
export async function createAndSubmitClaim(
vcClaim: GenericVerifiableCredential,
identity: IIdentifier,
issuerDid: string,
apiServer: string,
axios: Axios,
): Promise<CreateAndSubmitClaimResult> {
@ -690,34 +692,15 @@ export async function createAndSubmitClaim(
},
};
// Create a signature using private key of identity
const firstKey = identity.keys[0];
const privateKeyHex = firstKey?.privateKeyHex;
if (!privateKeyHex) {
throw {
error: "No private key",
message: `Your identifier ${identity.did} is not configured correctly. Use a different identifier.`,
};
}
const signer = await SimpleSigner(privateKeyHex);
// Create a JWT for the request
const vcJwt: string = await didJwt.createJWT(vcPayload, {
issuer: identity.did,
signer,
});
const vcJwt: string = await createEndorserJwt(issuerDid, vcPayload);
// Make the xhr request payload
const payload = JSON.stringify({ jwtEncoded: vcJwt });
const url = `${apiServer}/api/v2/claim`;
const token = await accessToken(identity.did);
const response = await axios.post(url, payload, {
headers: {
"Content-Type": "application/json",
Authorization: `Bearer ${token}`,
},
});
@ -942,21 +925,36 @@ export const bvcMeetingJoinClaim = (did: string, startTime: string) => {
};
};
export async function createEndorserJwt(did: string, payload: object) {
const account = await getAccount(did);
export async function createEndorserJwtVcFromClaim(
issuerDid: string,
claim: object,
) {
// Make a payload for the claim
const vcPayload = {
vc: {
"@context": ["https://www.w3.org/2018/credentials/v1"],
type: ["VerifiableCredential"],
credentialSubject: claim,
},
};
return createEndorserJwt(issuerDid, vcPayload);
}
export async function createEndorserJwt(issuerDid: string, payload: object) {
const account = await getAccount(issuerDid);
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;
const signer = await SimpleSigner(privateKeyHex);
return didJwt.createJWT(payload, {
issuer: did,
issuer: issuerDid,
signer: signer,
});
} else if (account?.passkeyCredIdHex) {
return createDidPeerJwt(did, account.passkeyCredIdHex, payload);
return createDidPeerJwt(issuerDid, account.passkeyCredIdHex, payload);
} else {
throw new Error("No identity data found to sign for DID " + did);
throw new Error("No identity data found to sign for DID " + issuerDid);
}
}
@ -1044,16 +1042,16 @@ export async function setVisibilityUtil(
*
* @param apiServer endorser server URL string
* @param axios Axios instance
* @param {IIdentifier} identity - The identity object to check rate limits for.
* @param {string} issuerDid - The DID for which to check rate limits.
* @returns {Promise<AxiosResponse>} The Axios response object.
*/
export async function fetchEndorserRateLimits(
apiServer: string,
axios: Axios,
did: string,
issuerDid: string,
) {
const url = `${apiServer}/api/report/rateLimits`;
const headers = await getHeaders(did);
const headers = await getHeaders(issuerDid);
return await axios.get(url, { headers } as AxiosRequestConfig);
}
@ -1062,15 +1060,11 @@ export async function fetchEndorserRateLimits(
*
* @param apiServer image server URL string
* @param axios Axios instance
* @param {IIdentifier} identity - The identity object to check rate limits for.
* @param {string} issuerDid - The DID for which to check rate limits.
* @returns {Promise<AxiosResponse>} The Axios response object.
*/
export async function fetchImageRateLimits(
apiServer: string,
axios: Axios,
did: string,
) {
export async function fetchImageRateLimits(axios: Axios, issuerDid: string) {
const url = DEFAULT_IMAGE_API_SERVER + "/image-limits";
const headers = await getHeaders(did);
const headers = await getHeaders(issuerDid);
return await axios.get(url, { headers } as AxiosRequestConfig);
}

2
src/libs/util.ts

@ -16,7 +16,7 @@ import { createPeerDid, registerCredential } from "@/libs/didPeer";
import { Buffer } from "buffer";
export const PRIVACY_MESSAGE =
"The data you send be visible to the world -- except: your IDs and the IDs of anyone you tag will stay private, only visible to those you allow.";
"The data you send will be visible to the world -- except: your IDs and the IDs of anyone you tag will stay private, only visible to them and others you explicitly allow.";
/* eslint-disable prettier/prettier */
export const UNIT_SHORT: Record<string, string> = {

3
src/test/index.ts

@ -6,6 +6,9 @@ import { SERVICE_ID } from "../libs/endorserServer";
import { deriveAddress, newIdentifier } from "../libs/crypto";
import { MASTER_SETTINGS_KEY } from "@/db/tables/settings";
/**
* Get User #0 to sign & submit a RegisterAction for the user's activeDid.
*/
export async function testServerRegisterUser() {
const testUser0Mnem =
"seminar accuse mystery assist delay law thing deal image undo guard initial shallow wrestle list fragile borrow velvet tomorrow awake explain test offer control";

89
src/views/AccountViewView.vue

@ -359,6 +359,7 @@
<div class="text-slate-500 text-sm font-bold">Derivation Path</div>
<div
v-if="derivationPath"
class="text-sm text-slate-500 flex justify-start items-center mb-1"
>
<code class="truncate">{{ derivationPath }}</code>
@ -375,6 +376,12 @@
</button>
<span v-show="showDerCopy">Copied</span>
</div>
<div
v-else
class="text-sm text-slate-500 flex justify-start items-center mb-1"
>
(none)
</div>
</div>
<!-- id used by puppeteer test script -->
@ -646,13 +653,16 @@
<script lang="ts">
import { AxiosError } from "axios";
import { Buffer } from "buffer/";
import Dexie from "dexie";
import "dexie-export-import";
import { ImportProgress } from "dexie-export-import/dist/import";
import { IIdentifier } from "@veramo/core";
import { ref } from "vue";
import { Component, Vue } from "vue-facing-decorator";
import { useClipboard } from "@vueuse/core";
import EntityIcon from "@/components/EntityIcon.vue";
import ImageMethodDialog from "@/components/ImageMethodDialog.vue";
import QuickNav from "@/components/QuickNav.vue";
import TopMessage from "@/components/TopMessage.vue";
@ -664,9 +674,9 @@ import {
NotificationIface,
} from "@/constants/app";
import { db, accountsDB } from "@/db/index";
import { Account } from "@/db/tables/accounts";
import { MASTER_SETTINGS_KEY, Settings } from "@/db/tables/settings";
import { accessToken } from "@/libs/crypto";
import { IIdentifier } from "@veramo/core";
import {
ErrorResponse,
EndorserRateLimits,
@ -674,15 +684,7 @@ import {
fetchEndorserRateLimits,
fetchImageRateLimits,
} from "@/libs/endorserServer";
import { Buffer } from "buffer/";
import EntityIcon from "@/components/EntityIcon.vue";
interface IAccount {
did: string;
publicKeyHex: string;
privateHex?: string;
derivationPath: string;
}
import { getAccount } from "@/libs/util";
const inputImportFileNameRef = ref<Blob>();
@ -705,6 +707,7 @@ export default class AccountViewView extends Vue {
givenName = "";
hideRegisterPromptOnNewContact = false;
imageLimits: ImageRateLimits | null = null;
imageServer = "";
isRegistered = false;
isSubscribed = false;
limitsMessage = "";
@ -738,18 +741,9 @@ export default class AccountViewView extends Vue {
*/
async mounted() {
try {
await db.open();
const settings = await db.settings.get(MASTER_SETTINGS_KEY);
// Initialize component state with values from the database or defaults
this.initializeState(settings);
// Get and process the identity
const identity = await this.getIdentity(this.activeDid);
if (identity) {
this.processIdentity(identity);
}
await this.initializeState();
await this.processIdentity();
const registration = await navigator.serviceWorker.ready;
this.subscription = await registration.pushManager.getSubscription();
@ -768,9 +762,12 @@ export default class AccountViewView extends Vue {
/**
* Initializes component state with values from the database or defaults.
* @param {SettingsType} settings - Object containing settings from the database.
*/
initializeState(settings: Settings | undefined) {
async initializeState() {
await db.open();
const settings: Settings | undefined =
await db.settings.get(MASTER_SETTINGS_KEY);
this.activeDid = (settings?.activeDid as string) || "";
this.apiServer = (settings?.apiServer as string) || "";
this.apiServerInput = (settings?.apiServer as string) || "";
@ -778,6 +775,7 @@ export default class AccountViewView extends Vue {
(settings?.firstName || "") +
(settings?.lastName ? ` ${settings.lastName}` : ""); // pre v 0.1.3
this.isRegistered = !!settings?.isRegistered;
this.imageServer = (settings?.imageServer as string) || "";
this.profileImageUrl = settings?.profileImageUrl as string;
this.showContactGives = !!settings?.showContactGivesInline;
this.hideRegisterPromptOnNewContact =
@ -790,23 +788,6 @@ export default class AccountViewView extends Vue {
this.webPushServerInput = (settings?.webPushServer as string) || "";
}
public async getIdentity(activeDid: string): Promise<IIdentifier | null> {
try {
// Open the accounts database
await accountsDB.open();
// Search for the account with the matching DID (decentralized identifier)
const account: { identity?: string } | undefined =
await accountsDB.accounts.where("did").equals(activeDid).first();
// Return parsed identity or null if not found
return JSON.parse((account?.identity as string) || "null");
} catch (error) {
console.error("Failed to find account:", error);
return null;
}
}
// call fn, copy text to the clipboard, then redo fn after 2 seconds
doCopyTwoSecRedo(text: string, fn: () => void) {
fn();
@ -846,21 +827,19 @@ export default class AccountViewView extends Vue {
/**
* Processes the identity and updates the component's state.
* @param {IdentityType} identity - Object containing identity information.
*/
processIdentity(identity: IIdentifier) {
if (
identity &&
identity.keys &&
identity.keys.length > 0 &&
identity.keys[0].meta
) {
async processIdentity() {
const account: Account | undefined = await getAccount(this.activeDid);
if (account?.identity) {
const identity = JSON.parse(account.identity as string) as IIdentifier;
this.publicHex = identity.keys[0].publicKeyHex;
this.publicBase64 = Buffer.from(this.publicHex, "hex").toString("base64");
this.derivationPath = identity.keys[0].meta?.derivationPath as string;
this.checkLimitsFor(this.activeDid);
} else {
// Handle the case where any of these are null or undefined
} else if (account?.publicKeyHex) {
this.publicHex = account.publicKeyHex as string;
this.publicBase64 = Buffer.from(this.publicHex, "hex").toString("base64");
this.checkLimitsFor(this.activeDid);
}
}
@ -1258,11 +1237,7 @@ export default class AccountViewView extends Vue {
);
}
}
const imageResp = await fetchImageRateLimits(
this.apiServer,
this.axios,
did,
);
const imageResp = await fetchImageRateLimits(this.axios, did);
if (imageResp.status === 200) {
this.imageLimits = imageResp.data;
}
@ -1359,9 +1334,9 @@ export default class AccountViewView extends Vue {
*
* @param {AccountType} account - The account object.
*/
private updateActiveAccountProperties(account: IAccount) {
private updateActiveAccountProperties(account: Account) {
this.activeDid = account.did;
this.derivationPath = account.derivationPath;
this.derivationPath = account.derivationPath || "";
this.publicHex = account.publicKeyHex;
this.publicBase64 = Buffer.from(this.publicHex, "hex").toString("base64");
}

2
src/views/ClaimAddRawView.vue

@ -84,7 +84,7 @@ export default class ClaimAddRawView extends Vue {
const fullClaim = JSON.parse(this.claimStr);
const result = await serverUtil.createAndSubmitClaim(
fullClaim,
await this.getIdentity(this.activeDid),
this.activeDid,
this.apiServer,
this.axios,
);

2
src/views/ClaimView.vue

@ -738,7 +738,7 @@ export default class ClaimView extends Vue {
};
const result = await serverUtil.createAndSubmitClaim(
confirmationClaim,
await this.getIdentity(this.activeDid),
this.activeDid,
this.apiServer,
this.axios,
);

2
src/views/ConfirmGiftView.vue

@ -744,7 +744,7 @@ export default class ClaimView extends Vue {
};
const result = await serverUtil.createAndSubmitClaim(
confirmationClaim,
await this.getIdentity(this.activeDid),
this.activeDid,
this.apiServer,
this.axios,
);

97
src/views/ContactAmountsView.vue

@ -106,7 +106,6 @@
<script lang="ts">
import { AxiosError } from "axios";
import * as didJwt from "did-jwt";
import * as R from "ramda";
import { Component, Vue } from "vue-facing-decorator";
@ -115,9 +114,10 @@ import { NotificationIface } from "@/constants/app";
import { accountsDB, db } from "@/db/index";
import { Contact } from "@/db/tables/contacts";
import { MASTER_SETTINGS_KEY } from "@/db/tables/settings";
import { accessToken, SimpleSigner } from "@/libs/crypto";
import { accessToken } from "@/libs/crypto";
import {
AgreeVerifiableCredential,
createEndorserJwtVcFromClaim,
displayAmount,
getHeaders,
GiveSummaryRecord,
@ -280,67 +280,48 @@ export default class ContactAmountssView extends Vue {
object: origClaim,
};
// Make a payload for the claim
const vcPayload: didJwt.JWTPayload = {
vc: {
"@context": ["https://www.w3.org/2018/credentials/v1"],
type: ["VerifiableCredential"],
credentialSubject: vcClaim,
},
};
// Create a signature using private key of identity
const identity = await this.getIdentity(this.activeDid);
if (identity.keys[0].privateKeyHex !== null) {
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
const privateKeyHex: string = identity.keys[0].privateKeyHex!;
const signer = await SimpleSigner(privateKeyHex);
const alg = undefined;
// Create a JWT for the request
const vcJwt: string = await didJwt.createJWT(vcPayload, {
alg: alg,
issuer: identity.did,
signer: signer,
});
const vcJwt: string = await createEndorserJwtVcFromClaim(
this.activeDid,
vcClaim,
);
// Make the xhr request payload
const payload = JSON.stringify({ jwtEncoded: vcJwt });
const url = this.apiServer + "/api/v2/claim";
const token = await accessToken(this.activeDid);
const headers = {
"Content-Type": "application/json",
Authorization: "Bearer " + token,
};
// Make the xhr request payload
const payload = JSON.stringify({ jwtEncoded: vcJwt });
const url = this.apiServer + "/api/v2/claim";
const token = await accessToken(this.activeDid);
const headers = {
"Content-Type": "application/json",
Authorization: "Bearer " + token,
};
try {
const resp = await this.axios.post(url, payload, { headers });
if (resp.data?.success) {
record.amountConfirmed =
(origClaim.object?.amountOfThisGood as number) || 1;
}
} catch (error) {
let userMessage = "There was an error. See logs for more info.";
const serverError = error as AxiosError;
if (serverError) {
if (serverError.message) {
userMessage = serverError.message; // Info for the user
} else {
userMessage = JSON.stringify(serverError.toJSON());
}
try {
const resp = await this.axios.post(url, payload, { headers });
if (resp.data?.success) {
record.amountConfirmed =
(origClaim.object?.amountOfThisGood as number) || 1;
}
} catch (error) {
let userMessage = "There was an error. See logs for more info.";
const serverError = error as AxiosError;
if (serverError) {
if (serverError.message) {
userMessage = serverError.message; // Info for the user
} else {
userMessage = error as string;
userMessage = JSON.stringify(serverError.toJSON());
}
// Now set that error for the user to see.
this.$notify(
{
group: "alert",
type: "danger",
title: "Error With Server",
text: userMessage,
},
-1,
);
} else {
userMessage = error as string;
}
// Now set that error for the user to see.
this.$notify(
{
group: "alert",
type: "danger",
title: "Error With Server",
text: userMessage,
},
-1,
);
}
}

12
src/views/ContactQRScanShowView.vue

@ -93,7 +93,7 @@ import {
SimpleSigner,
} from "@/libs/crypto";
import {
CONTACT_URL_PREFIX,
CONTACT_URL_PREFIX, createEndorserJwt,
ENDORSER_JWT_URL_LOCATION,
isDid,
register,
@ -161,15 +161,7 @@ export default class ContactQRScanShow extends Vue {
},
};
const alg = undefined;
const privateKeyHex: string = identity.keys[0].privateKeyHex;
const signer = await SimpleSigner(privateKeyHex);
// create a JWT for the request
const vcJwt: string = await didJwt.createJWT(contactInfo, {
alg: alg,
issuer: identity.did,
signer: signer,
});
const vcJwt: string = await createEndorserJwt(identity.did, contactInfo);
const viewPrefix = CONTACT_URL_PREFIX + ENDORSER_JWT_URL_LOCATION;
this.qrValue = viewPrefix + vcJwt;
}

18
src/views/ContactsView.vue

@ -303,12 +303,11 @@
import { AxiosError } from "axios";
import { IndexableType } from "dexie";
import * as R from "ramda";
import { IIdentifier } from "@veramo/core";
import { Component, Vue } from "vue-facing-decorator";
import { Router } from "vue-router";
import { AppString, NotificationIface } from "@/constants/app";
import { accountsDB, db } from "@/db/index";
import { db } from "@/db/index";
import { Contact } from "@/db/tables/contacts";
import { MASTER_SETTINGS_KEY, Settings } from "@/db/tables/settings";
import { getContactPayloadFromJwtUrl } from "@/libs/crypto";
@ -327,7 +326,6 @@ import QuickNav from "@/components/QuickNav.vue";
import EntityIcon from "@/components/EntityIcon.vue";
import GiftedDialog from "@/components/GiftedDialog.vue";
import OfferDialog from "@/components/OfferDialog.vue";
import { Account } from "@/db/tables/accounts";
import { Buffer } from "buffer/";
@ -401,20 +399,6 @@ export default class ContactsView extends Vue {
);
}
public async getIdentity(activeDid: string): Promise<IIdentifier> {
await accountsDB.open();
const accounts = await accountsDB.accounts.toArray();
const account = R.find((acc) => acc.did === activeDid, accounts) as Account;
const identity = JSON.parse(account?.identity || "null");
if (!identity) {
throw new Error(
"Attempted to load Give records with no identifier available.",
);
}
return identity;
}
async loadGives() {
if (!this.activeDid) {
return;

3
src/views/GiftedDetails.vue

@ -549,7 +549,6 @@ export default class GiftedDetails extends Vue {
*/
public async recordGive() {
try {
const identity = await libsUtil.getIdentity(this.activeDid);
const recipientDid = this.givenToRecipient
? this.recipientDid
: undefined;
@ -557,7 +556,7 @@ export default class GiftedDetails extends Vue {
const result = await createAndSubmitGive(
this.axios,
this.apiServer,
identity,
this.activeDid,
this.giverDid,
recipientDid,
this.description,

157
src/views/NewEditProjectView.vue

@ -174,7 +174,6 @@
<script lang="ts">
import "leaflet/dist/leaflet.css";
import { AxiosError } from "axios";
import * as didJwt from "did-jwt";
import { DateTime } from "luxon";
import { IIdentifier } from "@veramo/core";
import { Component, Vue } from "vue-facing-decorator";
@ -184,10 +183,13 @@ import QuickNav from "@/components/QuickNav.vue";
import { DEFAULT_IMAGE_API_SERVER, NotificationIface } from "@/constants/app";
import { accountsDB, db } from "@/db/index";
import { MASTER_SETTINGS_KEY } from "@/db/tables/settings";
import { accessToken, SimpleSigner } from "@/libs/crypto";
import { accessToken } from "@/libs/crypto";
import * as libsUtil from "@/libs/util";
import { useAppStore } from "@/store/app";
import { PlanVerifiableCredential } from "@/libs/endorserServer";
import {
createEndorserJwtVcFromClaim,
PlanVerifiableCredential,
} from "@/libs/endorserServer";
import ImageMethodDialog from "@/components/ImageMethodDialog.vue";
@Component({
@ -430,113 +432,88 @@ export default class NewEditProjectView extends Vue {
} else {
delete vcClaim.startTime;
}
// Make a payload for the claim
const vcPayload = {
vc: {
"@context": ["https://www.w3.org/2018/credentials/v1"],
type: ["VerifiableCredential"],
credentialSubject: vcClaim,
},
};
// create a signature using private key of identity
if (identity.keys[0].privateKeyHex != null) {
const privateKeyHex: string = identity.keys[0].privateKeyHex;
const signer = await SimpleSigner(privateKeyHex);
const alg = undefined;
// create a JWT for the request
const vcJwt: string = await didJwt.createJWT(
vcPayload as Partial<didJwt.JWTPayload>,
{
alg: alg,
issuer: identity.did,
signer: signer,
},
);
const vcJwt = await createEndorserJwtVcFromClaim(identity.did, vcClaim);
// Make the xhr request payload
// Make the xhr request payload
const payload = JSON.stringify({ jwtEncoded: vcJwt });
const url = this.apiServer + "/api/v2/claim";
const token = await accessToken(identity.did);
const headers = {
"Content-Type": "application/json",
Authorization: "Bearer " + token,
};
const payload = JSON.stringify({ jwtEncoded: vcJwt });
const url = this.apiServer + "/api/v2/claim";
const token = await accessToken(identity.did);
const headers = {
"Content-Type": "application/json",
Authorization: "Bearer " + token,
};
try {
const resp = await this.axios.post(url, payload, { headers });
if (resp.data?.success?.handleId) {
this.errorMessage = "";
useAppStore()
.setProjectId(resp.data.success.handleId)
.then(() => {
this.$router.push({ name: "project" });
});
} else {
console.error(
"Got unexpected 'data' inside response from server",
resp,
);
try {
const resp = await this.axios.post(url, payload, { headers });
if (resp.data?.success?.handleId) {
this.errorMessage = "";
useAppStore()
.setProjectId(resp.data.success.handleId)
.then(() => {
this.$router.push({ name: "project" });
});
} else {
console.error(
"Got unexpected 'data' inside response from server",
resp,
);
this.$notify(
{
group: "alert",
type: "danger",
title: "Error Saving Idea",
text: "Server did not save the idea. Try again.",
},
-1,
);
}
} catch (error) {
let userMessage = "There was an error saving the project.";
const serverError = error as AxiosError<{
error?: { message?: string };
}>;
if (serverError) {
console.error("Got error from server", serverError);
if (Object.prototype.hasOwnProperty.call(serverError, "message")) {
userMessage =
(serverError.response?.data?.error?.message as string) ||
userMessage;
this.$notify(
{
group: "alert",
type: "danger",
title: "Error Saving Idea",
text: "Server did not save the idea. Try again.",
title: "User Message",
text: userMessage,
},
-1,
);
}
} catch (error) {
let userMessage = "There was an error saving the project.";
const serverError = error as AxiosError<{
error?: { message?: string };
}>;
if (serverError) {
console.error("Got error from server", serverError);
if (Object.prototype.hasOwnProperty.call(serverError, "message")) {
userMessage =
(serverError.response?.data?.error?.message as string) ||
userMessage;
this.$notify(
{
group: "alert",
type: "danger",
title: "User Message",
text: userMessage,
},
-1,
);
} else {
this.$notify(
{
group: "alert",
type: "danger",
title: "Server Message",
text: JSON.stringify(serverError.toJSON()),
},
-1,
);
}
} else {
console.error(
"Here's the full error trying to save the claim:",
error,
);
this.$notify(
{
group: "alert",
type: "danger",
title: "Claim Error",
text: error as string,
title: "Server Message",
text: JSON.stringify(serverError.toJSON()),
},
-1,
);
}
// Now set that error for the user to see.
this.errorMessage = userMessage;
} else {
console.error("Here's the full error trying to save the claim:", error);
this.$notify(
{
group: "alert",
type: "danger",
title: "Claim Error",
text: error as string,
},
-1,
);
}
// Now set that error for the user to see.
this.errorMessage = userMessage;
}
}

2
src/views/ProjectViewView.vue

@ -981,7 +981,7 @@ export default class ProjectViewView extends Vue {
};
const result = await serverUtil.createAndSubmitClaim(
confirmationClaim,
await this.getIdentity(this.activeDid),
this.activeDid,
this.apiServer,
this.axios,
);

5
src/views/QuickActionBvcBeginView.vue

@ -124,7 +124,6 @@ export default class QuickActionBvcBeginView extends Vue {
try {
const hoursNum = libsUtil.numberOrZero(this.hoursStr);
const identity = await libsUtil.getIdentity(activeDid);
this.$notify({ group: "alert", type: "toast", title: "Sent..." }, 1000);
@ -134,7 +133,7 @@ export default class QuickActionBvcBeginView extends Vue {
const timeResult = await createAndSubmitGive(
axios,
apiServer,
identity,
activeDid,
activeDid,
undefined,
undefined,
@ -165,7 +164,7 @@ export default class QuickActionBvcBeginView extends Vue {
if (this.attended) {
const attendResult = await createAndSubmitClaim(
bvcMeetingJoinClaim(activeDid, this.todayOrPreviousStartDate),
identity,
activeDid,
apiServer,
axios,
);

8
src/views/QuickActionBvcEndView.vue

@ -157,7 +157,6 @@ import {
getHeaders,
ErrorResult,
} from "@/libs/endorserServer";
import * as libsUtil from "@/libs/util";
@Component({
methods: { claimSpecialDescription },
@ -264,8 +263,6 @@ export default class QuickActionBvcBeginView extends Vue {
async record() {
try {
const identity = await libsUtil.getIdentity(this.activeDid);
this.$notify({ group: "alert", type: "toast", title: "Sent..." }, 1000);
// in parallel, make a confirmation for each selected claim and send them all to the server
@ -277,9 +274,8 @@ export default class QuickActionBvcBeginView extends Vue {
if (!record) {
return { type: "error", error: "Record not found." };
}
const identity = await libsUtil.getIdentity(this.activeDid);
return createAndSubmitConfirmation(
identity,
this.activeDid,
record.claim as GenericVerifiableCredential,
record.id,
record.handleId,
@ -313,7 +309,7 @@ export default class QuickActionBvcBeginView extends Vue {
const giveResult = await createAndSubmitGive(
axios,
this.apiServer,
identity,
this.activeDid,
undefined,
this.activeDid,
this.description,

Loading…
Cancel
Save