fix some errors and correct recent type duplications & bloat (cherry-picked from d8f2587d1c)

This commit is contained in:
2025-05-31 22:36:15 -06:00
parent 4327a5175c
commit 24cfeca1eb
16 changed files with 264 additions and 346 deletions

View File

@@ -17,7 +17,7 @@ import { didEthLocalResolver } from "./did-eth-local-resolver";
import { PEER_DID_PREFIX, verifyPeerSignature } from "./didPeer";
import { base64urlDecodeString, createDidPeerJwt } from "./passkeyDidPeer";
import { urlBase64ToUint8Array } from "./util";
import { KeyMeta } from "../../../interfaces/common";
import { KeyMeta, KeyMetaWithPrivate } from "../../../interfaces/common";
export const ETHR_DID_PREFIX = "did:ethr:";
export const JWT_VERIFY_FAILED_CODE = "JWT_VERIFY_FAILED";
@@ -34,7 +34,7 @@ export function isFromPasskey(keyMeta?: KeyMeta): boolean {
}
export async function createEndorserJwtForKey(
account: KeyMeta,
account: KeyMetaWithPrivate,
payload: object,
expiresIn?: number,
) {

View File

@@ -38,7 +38,14 @@ import {
getPasskeyExpirationSeconds,
} from "../libs/util";
import { createEndorserJwtForKey } from "../libs/crypto/vc";
import { KeyMeta } from "../interfaces/common";
import {
GiveActionClaim,
JoinActionClaim,
OfferClaim,
PlanActionClaim,
RegisterActionClaim,
TenureClaim,
} from "../interfaces/claims";
import {
GenericCredWrapper,
@@ -46,15 +53,13 @@ import {
AxiosErrorResponse,
UserInfo,
CreateAndSubmitClaimResult,
PlanSummaryRecord,
GiveVerifiableCredential,
OfferVerifiableCredential,
RegisterVerifiableCredential,
ClaimObject,
VerifiableCredentialClaim,
Agent,
QuantitativeValue,
KeyMetaWithPrivate,
KeyMetaMaybeWithPrivate,
} from "../interfaces/common";
import { PlanSummaryRecord } from "../interfaces/records";
import { logger } from "../utils/logger";
import { PlatformServiceFactory } from "@/services/PlatformServiceFactory";
@@ -650,7 +655,7 @@ export async function getNewOffersToUserProjects(
* @param lastClaimId supplied when editing a previous claim
*/
export function hydrateGive(
vcClaimOrig?: GiveVerifiableCredential,
vcClaimOrig?: GiveActionClaim,
fromDid?: string,
toDid?: string,
description?: string,
@@ -662,8 +667,8 @@ export function hydrateGive(
imageUrl?: string,
providerPlanHandleId?: string,
lastClaimId?: string,
): GiveVerifiableCredential {
const vcClaim: GiveVerifiableCredential = vcClaimOrig
): GiveActionClaim {
const vcClaim: GiveActionClaim = vcClaimOrig
? R.clone(vcClaimOrig)
: {
"@context": SCHEMA_ORG_CONTEXT,
@@ -693,7 +698,7 @@ export function hydrateGive(
// Initialize fulfills array if not present
if (!Array.isArray(vcClaim.fulfills)) {
vcClaim.fulfills = [];
vcClaim.fulfills = vcClaim.fulfills ? [vcClaim.fulfills] : [];
}
// Filter and add fulfills elements
@@ -796,7 +801,7 @@ export async function createAndSubmitGive(
export async function editAndSubmitGive(
axios: Axios,
apiServer: string,
fullClaim: GenericCredWrapper<GiveVerifiableCredential>,
fullClaim: GenericCredWrapper<GiveActionClaim>,
issuerDid: string,
fromDid?: string,
toDid?: string,
@@ -837,7 +842,7 @@ export async function editAndSubmitGive(
* @param lastClaimId supplied when editing a previous claim
*/
export function hydrateOffer(
vcClaimOrig?: OfferVerifiableCredential,
vcClaimOrig?: OfferClaim,
fromDid?: string,
toDid?: string,
itemDescription?: string,
@@ -847,8 +852,8 @@ export function hydrateOffer(
fulfillsProjectHandleId?: string,
validThrough?: string,
lastClaimId?: string,
): OfferVerifiableCredential {
const vcClaim: OfferVerifiableCredential = vcClaimOrig
): OfferClaim {
const vcClaim: OfferClaim = vcClaimOrig
? R.clone(vcClaimOrig)
: {
"@context": SCHEMA_ORG_CONTEXT,
@@ -856,12 +861,13 @@ export function hydrateOffer(
};
if (lastClaimId) {
// this is an edit
vcClaim.lastClaimId = lastClaimId;
delete vcClaim.identifier;
}
if (fromDid) {
vcClaim.agent = { identifier: fromDid };
vcClaim.offeredBy = { identifier: fromDid };
}
if (toDid) {
vcClaim.recipient = { identifier: toDid };
@@ -869,13 +875,10 @@ export function hydrateOffer(
vcClaim.description = conditionDescription || undefined;
if (amount && !isNaN(amount)) {
const quantitativeValue: QuantitativeValue = {
"@context": SCHEMA_ORG_CONTEXT,
"@type": "QuantitativeValue",
vcClaim.includesObject = {
amountOfThisGood: amount,
unitCode: unitCode || "HUR",
};
vcClaim.object = quantitativeValue;
}
if (itemDescription || fulfillsProjectHandleId) {
@@ -928,7 +931,7 @@ export async function createAndSubmitOffer(
undefined,
);
return createAndSubmitClaim(
vcClaim as OfferVerifiableCredential,
vcClaim as OfferClaim,
issuerDid,
apiServer,
axios,
@@ -938,7 +941,7 @@ export async function createAndSubmitOffer(
export async function editAndSubmitOffer(
axios: Axios,
apiServer: string,
fullClaim: GenericCredWrapper<OfferVerifiableCredential>,
fullClaim: GenericCredWrapper<OfferClaim>,
issuerDid: string,
itemDescription: string,
amount?: number,
@@ -961,7 +964,7 @@ export async function editAndSubmitOffer(
fullClaim.id,
);
return createAndSubmitClaim(
vcClaim as OfferVerifiableCredential,
vcClaim as OfferClaim,
issuerDid,
apiServer,
axios,
@@ -1035,7 +1038,7 @@ export async function createAndSubmitClaim(
}
export async function generateEndorserJwtUrlForAccount(
account: KeyMeta,
account: KeyMetaMaybeWithPrivate,
isRegistered: boolean,
givenName: string,
profileImageUrl: string,
@@ -1059,7 +1062,7 @@ export async function generateEndorserJwtUrlForAccount(
}
// Add the next key -- not recommended for the QR code for such a high resolution
if (isContact) {
if (isContact && account.derivationPath && account.mnemonic) {
const newDerivPath = nextDerivationPath(account.derivationPath);
const nextPublicHex = deriveAddress(account.mnemonic, newDerivPath)[2];
const nextPublicEncKey = Buffer.from(nextPublicHex, "hex");
@@ -1081,7 +1084,11 @@ export async function createEndorserJwtForDid(
expiresIn?: number,
) {
const account = await retrieveFullyDecryptedAccount(issuerDid);
return createEndorserJwtForKey(account as KeyMeta, payload, expiresIn);
return createEndorserJwtForKey(
account as KeyMetaWithPrivate,
payload,
expiresIn,
);
}
/**
@@ -1178,102 +1185,118 @@ export const claimSpecialDescription = (
identifiers: Array<string>,
contacts: Array<Contact>,
) => {
let claim = record.claim;
let claim:
| GenericVerifiableCredential
| GenericCredWrapper<GenericVerifiableCredential> = record.claim;
if ("claim" in claim) {
// it's a nested GenericCredWrapper
claim = claim.claim as GenericVerifiableCredential;
}
const issuer = didInfo(record.issuer, activeDid, identifiers, contacts);
const claimObj = claim as ClaimObject;
const type = claimObj["@type"] || "UnknownType";
const type = claim["@type"] || "UnknownType";
if (type === "AgreeAction") {
return (
issuer +
" agreed with " +
claimSummary(claimObj.object as GenericVerifiableCredential)
claimSummary(claim.object as GenericVerifiableCredential)
);
} else if (isAccept(claim)) {
return (
issuer +
" accepted " +
claimSummary(claimObj.object as GenericVerifiableCredential)
claimSummary(claim.object as GenericVerifiableCredential)
);
} else if (type === "GiveAction") {
const giveClaim = claim as GiveVerifiableCredential;
const agent: Agent = giveClaim.agent || {
identifier: undefined,
did: undefined,
};
const agentDid = agent.did || agent.identifier;
const contactInfo = agentDid
? didInfo(agentDid, activeDid, identifiers, contacts)
: "someone";
const offering = giveClaim.object
? " " + claimSummary(giveClaim.object)
const giveClaim = claim as GiveActionClaim;
// @ts-expect-error because .did may be found in legacy data, before March 2023
const legacyGiverDid = giveClaim.agent?.did;
const giver = giveClaim.agent?.identifier || legacyGiverDid;
const giverInfo = didInfo(giver, activeDid, identifiers, contacts);
let gaveAmount = giveClaim.object?.amountOfThisGood
? displayAmount(
giveClaim.object.unitCode as string,
giveClaim.object.amountOfThisGood as number,
)
: "";
const recipient = giveClaim.participant?.identifier;
const recipientInfo = recipient
? " to " + didInfo(recipient, activeDid, identifiers, contacts)
if (giveClaim.description) {
if (gaveAmount) {
gaveAmount = gaveAmount + ", and also: ";
}
gaveAmount = gaveAmount + giveClaim.description;
}
if (!gaveAmount) {
gaveAmount = "something not described";
}
// @ts-expect-error because .did may be found in legacy data, before March 2023
const legacyRecipDid = giveClaim.recipient?.did;
const gaveRecipientId = giveClaim.recipient?.identifier || legacyRecipDid;
const gaveRecipientInfo = gaveRecipientId
? " to " + didInfo(gaveRecipientId, activeDid, identifiers, contacts)
: "";
return contactInfo + " gave" + offering + recipientInfo;
return giverInfo + " gave" + gaveRecipientInfo + ": " + gaveAmount;
} else if (type === "JoinAction") {
const joinClaim = claim as ClaimObject;
const agent: Agent = joinClaim.agent || {
identifier: undefined,
did: undefined,
};
const agentDid = agent.did || agent.identifier;
const contactInfo = agentDid
? didInfo(agentDid, activeDid, identifiers, contacts)
: "someone";
const object = joinClaim.object as GenericVerifiableCredential;
const objectInfo = object ? " " + claimSummary(object) : "";
return contactInfo + " joined" + objectInfo;
const joinClaim = claim as JoinActionClaim;
// @ts-expect-error because .did may be found in legacy data, before March 2023
const legacyDid = joinClaim.agent?.did;
const agent = joinClaim.agent?.identifier || legacyDid;
const contactInfo = didInfo(agent, activeDid, identifiers, contacts);
let eventOrganizer =
joinClaim.event &&
joinClaim.event.organizer &&
joinClaim.event.organizer.name;
eventOrganizer = eventOrganizer || "";
let eventName = joinClaim.event && joinClaim.event.name;
eventName = eventName ? " " + eventName : "";
let fullEvent = eventOrganizer + eventName;
fullEvent = fullEvent ? " attended the " + fullEvent : "";
let eventDate = joinClaim.event && joinClaim.event.startTime;
eventDate = eventDate ? " at " + eventDate : "";
return contactInfo + fullEvent + eventDate;
} else if (isOffer(claim)) {
const offerClaim = claim as OfferVerifiableCredential;
const agent: Agent = offerClaim.agent || {
identifier: undefined,
did: undefined,
};
const agentDid = agent.did || agent.identifier;
const contactInfo = agentDid
? didInfo(agentDid, activeDid, identifiers, contacts)
: "someone";
const offering = offerClaim.object
? " " + claimSummary(offerClaim.object)
: "";
const offerRecipientId = offerClaim.participant?.identifier;
const offerClaim = claim as OfferClaim;
const offerer = offerClaim.offeredBy?.identifier;
const contactInfo = didInfo(offerer, activeDid, identifiers, contacts);
let offering = "";
if (offerClaim.includesObject) {
offering +=
" " +
displayAmount(
offerClaim.includesObject.unitCode,
offerClaim.includesObject.amountOfThisGood,
);
}
if (offerClaim.itemOffered?.description) {
offering += ", saying: " + offerClaim.itemOffered?.description;
}
// @ts-expect-error because .did may be found in legacy data, before March 2023
const legacyDid = offerClaim.recipient?.did;
const offerRecipientId = offerClaim.recipient?.identifier || legacyDid;
const offerRecipientInfo = offerRecipientId
? " to " + didInfo(offerRecipientId, activeDid, identifiers, contacts)
: "";
return contactInfo + " offered" + offering + offerRecipientInfo;
} else if (type === "PlanAction") {
const planClaim = claim as ClaimObject;
const agent: Agent = planClaim.agent || {
identifier: undefined,
did: undefined,
};
const agentDid = agent.did || agent.identifier;
const contactInfo = agentDid
? didInfo(agentDid, activeDid, identifiers, contacts)
: "someone";
const object = planClaim.object as GenericVerifiableCredential;
const objectInfo = object ? " " + claimSummary(object) : "";
return contactInfo + " planned" + objectInfo;
const planClaim = claim as PlanActionClaim;
const claimer = planClaim.agent?.identifier || record.issuer;
const claimerInfo = didInfo(claimer, activeDid, identifiers, contacts);
return claimerInfo + " announced a project: " + planClaim.name;
} else if (type === "Tenure") {
const tenureClaim = claim as ClaimObject;
const agent: Agent = tenureClaim.agent || {
identifier: undefined,
did: undefined,
};
const agentDid = agent.did || agent.identifier;
const contactInfo = agentDid
? didInfo(agentDid, activeDid, identifiers, contacts)
: "someone";
const object = tenureClaim.object as GenericVerifiableCredential;
const objectInfo = object ? " " + claimSummary(object) : "";
return contactInfo + " has tenure" + objectInfo;
const tenureClaim = claim as TenureClaim;
// @ts-expect-error because .did may be found in legacy data, before March 2023
const legacyDid = tenureClaim.party?.did;
const claimer = tenureClaim.party?.identifier || legacyDid;
const contactInfo = didInfo(claimer, activeDid, identifiers, contacts);
const polygon = tenureClaim.spatialUnit?.geo?.polygon || "";
return (
contactInfo +
" possesses [" +
polygon.substring(0, polygon.indexOf(" ")) +
"...]"
);
} else {
return issuer + " declared " + claimSummary(claim);
}
@@ -1330,7 +1353,7 @@ export async function createInviteJwt(
identifier?: string,
expiresIn?: number, // in seconds
): Promise<string> {
const vcClaim: RegisterVerifiableCredential = {
const vcClaim: RegisterActionClaim = {
"@context": SCHEMA_ORG_CONTEXT,
"@type": "RegisterAction",
agent: { identifier: activeDid },

View File

@@ -34,10 +34,10 @@ import { containsHiddenDid } from "../libs/endorserServer";
import {
GenericCredWrapper,
GenericVerifiableCredential,
KeyMetaWithPrivate,
} from "../interfaces/common";
import { GiveSummaryRecord } from "../interfaces/records";
import { OfferVerifiableCredential } from "../interfaces/claims";
import { KeyMeta } from "../interfaces/common";
import { OfferClaim } from "../interfaces/claims";
import { createPeerDid } from "../libs/crypto/vc/didPeer";
import { registerCredential } from "../libs/crypto/vc/passkeyDidPeer";
import { logger } from "../utils/logger";
@@ -391,17 +391,19 @@ export function base64ToBlob(base64DataUrl: string, sliceSize = 512) {
* @param veriClaim is expected to have fields: claim and issuer
*/
export function offerGiverDid(
veriClaim: GenericCredWrapper<GenericVerifiableCredential>,
veriClaim: GenericCredWrapper<OfferClaim>,
): string | undefined {
let giver;
const claim = veriClaim.claim as OfferVerifiableCredential;
const offeredBy: { identifier?: string } | undefined =
claim.offeredBy || claim.credentialSubject?.offeredBy;
const offeredById = offeredBy?.identifier;
if (offeredById && !serverUtil.isHiddenDid(offeredById)) {
giver = offeredById;
} else if (veriClaim.issuer && !serverUtil.isHiddenDid(veriClaim.issuer)) {
giver = veriClaim.issuer;
const innerClaim = veriClaim.claim as OfferClaim;
let giver: string | undefined = undefined;
giver = innerClaim.offeredBy?.identifier;
if (giver && !serverUtil.isHiddenDid(giver)) {
return giver;
}
giver = veriClaim.issuer;
if (giver && !serverUtil.isHiddenDid(giver)) {
return giver;
}
return giver;
}
@@ -413,7 +415,10 @@ export function offerGiverDid(
export const canFulfillOffer = (
veriClaim: GenericCredWrapper<GenericVerifiableCredential>,
) => {
return veriClaim.claimType === "Offer" && !!offerGiverDid(veriClaim);
return (
veriClaim.claimType === "Offer" &&
!!offerGiverDid(veriClaim as GenericCredWrapper<OfferClaim>)
);
};
// return object with paths and arrays of DIDs for any keys ending in "VisibleToDid"
@@ -482,11 +487,7 @@ export function findAllVisibleToDids(
*
**/
export interface AccountKeyInfo
extends Omit<Account, "derivationPath">,
Omit<KeyMeta, "derivationPath"> {
derivationPath?: string; // Make it optional to match Account type
}
export type AccountKeyInfo = Account & KeyMetaWithPrivate;
export const retrieveAccountCount = async (): Promise<number> => {
let result = 0;
@@ -523,12 +524,16 @@ export const retrieveAccountDids = async (): Promise<string[]> => {
return allDids;
};
// This is provided and recommended when the full key is not necessary so that
// future work could separate this info from the sensitive key material.
/**
* This is provided and recommended when the full key is not necessary so that
* future work could separate this info from the sensitive key material.
*
* If you need the private key data, use retrieveFullyDecryptedAccount instead.
*/
export const retrieveAccountMetadata = async (
activeDid: string,
): Promise<AccountKeyInfo | undefined> => {
let result: AccountKeyInfo | undefined = undefined;
): Promise<Account | undefined> => {
let result: Account | undefined = undefined;
const platformService = PlatformServiceFactory.getInstance();
const dbAccount = await platformService.dbQuery(
`SELECT * FROM accounts WHERE did = ?`,
@@ -560,33 +565,16 @@ export const retrieveAccountMetadata = async (
return result;
};
export const retrieveAllAccountsMetadata = async (): Promise<Account[]> => {
const platformService = PlatformServiceFactory.getInstance();
const sql = `SELECT * FROM accounts`;
const dbAccounts = await platformService.dbQuery(sql);
const accounts = databaseUtil.mapQueryResultToValues(dbAccounts) as Account[];
let result = accounts.map((account) => {
// eslint-disable-next-line @typescript-eslint/no-unused-vars
const { identity, mnemonic, ...metadata } = account;
return metadata as Account;
});
if (USE_DEXIE_DB) {
// one of the few times we use accountsDBPromise directly; try to avoid more usage
const accountsDB = await accountsDBPromise;
const array = await accountsDB.accounts.toArray();
result = array.map((account) => {
// eslint-disable-next-line @typescript-eslint/no-unused-vars
const { identity, mnemonic, ...metadata } = account;
return metadata as Account;
});
}
return result;
};
/**
* This contains sensitive data. If possible, use retrieveAccountMetadata instead.
*
* @param activeDid
* @returns account info with private key data decrypted
*/
export const retrieveFullyDecryptedAccount = async (
activeDid: string,
): Promise<AccountKeyInfo | undefined> => {
let result: AccountKeyInfo | undefined = undefined;
): Promise<Account | undefined> => {
let result: Account | undefined = undefined;
const platformService = PlatformServiceFactory.getInstance();
const dbSecrets = await platformService.dbQuery(
`SELECT secretBase64 from secret`,
@@ -634,20 +622,26 @@ export const retrieveFullyDecryptedAccount = async (
return result;
};
// let's try and eliminate this
export const retrieveAllFullyDecryptedAccounts = async (): Promise<
Array<AccountEncrypted>
> => {
export const retrieveAllAccountsMetadata = async (): Promise<Account[]> => {
const platformService = PlatformServiceFactory.getInstance();
const queryResult = await platformService.dbQuery("SELECT * FROM accounts");
let allAccounts = databaseUtil.mapQueryResultToValues(
queryResult,
) as unknown as AccountEncrypted[];
const dbAccounts = await platformService.dbQuery(`SELECT * FROM accounts`);
const accounts = databaseUtil.mapQueryResultToValues(dbAccounts) as Account[];
let result = accounts.map((account) => {
// eslint-disable-next-line @typescript-eslint/no-unused-vars
const { identity, mnemonic, ...metadata } = account;
return metadata as Account;
});
if (USE_DEXIE_DB) {
// one of the few times we use accountsDBPromise directly; try to avoid more usage
const accountsDB = await accountsDBPromise;
allAccounts = (await accountsDB.accounts.toArray()) as AccountEncrypted[];
const array = await accountsDB.accounts.toArray();
result = array.map((account) => {
// eslint-disable-next-line @typescript-eslint/no-unused-vars
const { identity, mnemonic, ...metadata } = account;
return metadata as Account;
});
}
return allAccounts;
return result;
};
/**