|
@ -2,7 +2,6 @@ import { |
|
|
Axios, |
|
|
Axios, |
|
|
AxiosRequestConfig, |
|
|
AxiosRequestConfig, |
|
|
AxiosResponse, |
|
|
AxiosResponse, |
|
|
RawAxiosRequestHeaders, |
|
|
|
|
|
} from "axios"; |
|
|
} from "axios"; |
|
|
import * as didJwt from "did-jwt"; |
|
|
import * as didJwt from "did-jwt"; |
|
|
import { LRUCache } from "lru-cache"; |
|
|
import { LRUCache } from "lru-cache"; |
|
@ -13,7 +12,8 @@ import { DEFAULT_IMAGE_API_SERVER } from "@/constants/app"; |
|
|
import { Contact } from "@/db/tables/contacts"; |
|
|
import { Contact } from "@/db/tables/contacts"; |
|
|
import { accessToken, SimpleSigner } from "@/libs/crypto"; |
|
|
import { accessToken, SimpleSigner } from "@/libs/crypto"; |
|
|
import { NonsensitiveDexie } from "@/db/index"; |
|
|
import { NonsensitiveDexie } from "@/db/index"; |
|
|
import { getIdentity } from "@/libs/util"; |
|
|
import { createDidPeerJwt } from "@/libs/didPeer"; |
|
|
|
|
|
import { getAccount, getIdentity } from "@/libs/util"; |
|
|
|
|
|
|
|
|
export const SCHEMA_ORG_CONTEXT = "https://schema.org"; |
|
|
export const SCHEMA_ORG_CONTEXT = "https://schema.org"; |
|
|
// the object in RegisterAction claims
|
|
|
// the object in RegisterAction claims
|
|
@ -160,7 +160,7 @@ export interface OfferVerifiableCredential { |
|
|
// Note that previous VCs may have additional fields.
|
|
|
// Note that previous VCs may have additional fields.
|
|
|
// https://endorser.ch/doc/html/transactions.html#id7
|
|
|
// https://endorser.ch/doc/html/transactions.html#id7
|
|
|
export interface PlanVerifiableCredential { |
|
|
export interface PlanVerifiableCredential { |
|
|
"@context": SCHEMA_ORG_CONTEXT; |
|
|
"@context": "https://schema.org"; |
|
|
"@type": "PlanAction"; |
|
|
"@type": "PlanAction"; |
|
|
name: string; |
|
|
name: string; |
|
|
agent?: { identifier: string }; |
|
|
agent?: { identifier: string }; |
|
@ -453,28 +453,30 @@ export function didInfo( |
|
|
return didInfoForContact(did, activeDid, contact, allMyDids).displayName; |
|
|
return didInfoForContact(did, activeDid, contact, allMyDids).displayName; |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
async function getHeaders(identity: IIdentifier | null) { |
|
|
export async function getHeaders(did?: string) { |
|
|
const headers: RawAxiosRequestHeaders = { |
|
|
const headers: { "Content-Type": string; Authorization?: string } = { |
|
|
"Content-Type": "application/json", |
|
|
"Content-Type": "application/json", |
|
|
}; |
|
|
}; |
|
|
if (identity) { |
|
|
if (did) { |
|
|
const token = await accessToken(identity); |
|
|
const token = await accessToken(undefined, did); |
|
|
headers["Authorization"] = "Bearer " + token; |
|
|
headers["Authorization"] = "Bearer " + token; |
|
|
|
|
|
} else { |
|
|
|
|
|
// it's often OK to request without auth; we assume necessary checks are done earlier
|
|
|
} |
|
|
} |
|
|
return headers; |
|
|
return headers; |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
/** |
|
|
/** |
|
|
* @param handleId nullable, in which case "undefined" will be returned |
|
|
* @param handleId nullable, in which case "undefined" will be returned |
|
|
* @param identity nullable, in which case no private info will be returned |
|
|
* @param requesterDid optional, in which case no private info will be returned |
|
|
* @param axios |
|
|
* @param axios |
|
|
* @param apiServer |
|
|
* @param apiServer |
|
|
*/ |
|
|
*/ |
|
|
export async function getPlanFromCache( |
|
|
export async function getPlanFromCache( |
|
|
handleId: string | null, |
|
|
handleId: string | null, |
|
|
identity: IIdentifier | null, |
|
|
|
|
|
axios: Axios, |
|
|
axios: Axios, |
|
|
apiServer: string, |
|
|
apiServer: string, |
|
|
|
|
|
requesterDid?: string, |
|
|
): Promise<PlanSummaryRecord | undefined> { |
|
|
): Promise<PlanSummaryRecord | undefined> { |
|
|
if (!handleId) { |
|
|
if (!handleId) { |
|
|
return undefined; |
|
|
return undefined; |
|
@ -485,7 +487,7 @@ export async function getPlanFromCache( |
|
|
apiServer + |
|
|
apiServer + |
|
|
"/api/v2/report/plans?handleId=" + |
|
|
"/api/v2/report/plans?handleId=" + |
|
|
encodeURIComponent(handleId); |
|
|
encodeURIComponent(handleId); |
|
|
const headers = await getHeaders(identity); |
|
|
const headers = await getHeaders(requesterDid); |
|
|
try { |
|
|
try { |
|
|
const resp = await axios.get(url, { headers }); |
|
|
const resp = await axios.get(url, { headers }); |
|
|
if (resp.status === 200 && resp.data?.data?.length > 0) { |
|
|
if (resp.status === 200 && resp.data?.data?.length > 0) { |
|
@ -944,18 +946,34 @@ export const bvcMeetingJoinClaim = (did: string, startTime: string) => { |
|
|
}; |
|
|
}; |
|
|
}; |
|
|
}; |
|
|
|
|
|
|
|
|
|
|
|
export async function createEndorserJwt(did: string, payload: object) { |
|
|
|
|
|
const account = await getAccount(did); |
|
|
|
|
|
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, |
|
|
|
|
|
signer: signer, |
|
|
|
|
|
}); |
|
|
|
|
|
} else if (account.passkeyCredIdHex) { |
|
|
|
|
|
return createDidPeerJwt(did, account.passkeyCredIdHex, payload); |
|
|
|
|
|
} else { |
|
|
|
|
|
throw new Error("No identity data found to sign for DID " + did); |
|
|
|
|
|
} |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
export async function register( |
|
|
export async function register( |
|
|
activeDid: string, |
|
|
activeDid: string, |
|
|
apiServer: string, |
|
|
apiServer: string, |
|
|
axios: Axios, |
|
|
axios: Axios, |
|
|
contact: Contact, |
|
|
contact: Contact, |
|
|
) { |
|
|
) { |
|
|
const identity = await getIdentity(activeDid); |
|
|
|
|
|
|
|
|
|
|
|
const vcClaim: RegisterVerifiableCredential = { |
|
|
const vcClaim: RegisterVerifiableCredential = { |
|
|
"@context": SCHEMA_ORG_CONTEXT, |
|
|
"@context": SCHEMA_ORG_CONTEXT, |
|
|
"@type": "RegisterAction", |
|
|
"@type": "RegisterAction", |
|
|
agent: { identifier: identity.did }, |
|
|
agent: { identifier: activeDid }, |
|
|
object: SERVICE_ID, |
|
|
object: SERVICE_ID, |
|
|
participant: { identifier: contact.did }, |
|
|
participant: { identifier: contact.did }, |
|
|
}; |
|
|
}; |
|
@ -968,26 +986,10 @@ export async function register( |
|
|
}, |
|
|
}, |
|
|
}; |
|
|
}; |
|
|
// Create a signature using private key of identity
|
|
|
// Create a signature using private key of identity
|
|
|
if (identity.keys[0].privateKeyHex == null) { |
|
|
const vcJwt = await createEndorserJwt(activeDid, vcPayload); |
|
|
return { error: "Private key not found." }; |
|
|
|
|
|
} |
|
|
|
|
|
// 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, |
|
|
|
|
|
}); |
|
|
|
|
|
|
|
|
|
|
|
// Make the xhr request payload
|
|
|
|
|
|
const payload = JSON.stringify({ jwtEncoded: vcJwt }); |
|
|
|
|
|
const url = apiServer + "/api/v2/claim"; |
|
|
const url = apiServer + "/api/v2/claim"; |
|
|
const headers = await getHeaders(identity); |
|
|
const resp = await axios.post(url, { jwtEncoded: vcJwt }); |
|
|
|
|
|
|
|
|
const resp = await axios.post(url, payload, { headers }); |
|
|
|
|
|
if (resp.data?.success?.handleId) { |
|
|
if (resp.data?.success?.handleId) { |
|
|
return { success: true }; |
|
|
return { success: true }; |
|
|
} else if (resp.data?.success?.embeddedRecordError) { |
|
|
} else if (resp.data?.success?.embeddedRecordError) { |
|
@ -1017,7 +1019,7 @@ export async function setVisibilityUtil( |
|
|
const url = |
|
|
const url = |
|
|
apiServer + "/api/report/" + (visibility ? "canSeeMe" : "cannotSeeMe"); |
|
|
apiServer + "/api/report/" + (visibility ? "canSeeMe" : "cannotSeeMe"); |
|
|
const identity = await getIdentity(activeDid); |
|
|
const identity = await getIdentity(activeDid); |
|
|
const headers = await getHeaders(identity); |
|
|
const headers = await getHeaders(identity.did); |
|
|
const payload = JSON.stringify({ did: contact.did }); |
|
|
const payload = JSON.stringify({ did: contact.did }); |
|
|
|
|
|
|
|
|
try { |
|
|
try { |
|
@ -1052,10 +1054,10 @@ export async function setVisibilityUtil( |
|
|
export async function fetchEndorserRateLimits( |
|
|
export async function fetchEndorserRateLimits( |
|
|
apiServer: string, |
|
|
apiServer: string, |
|
|
axios: Axios, |
|
|
axios: Axios, |
|
|
identity: IIdentifier, |
|
|
did: string, |
|
|
) { |
|
|
) { |
|
|
const url = `${apiServer}/api/report/rateLimits`; |
|
|
const url = `${apiServer}/api/report/rateLimits`; |
|
|
const headers = await getHeaders(identity); |
|
|
const headers = await getHeaders(did); |
|
|
return await axios.get(url, { headers } as AxiosRequestConfig); |
|
|
return await axios.get(url, { headers } as AxiosRequestConfig); |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
@ -1070,9 +1072,9 @@ export async function fetchEndorserRateLimits( |
|
|
export async function fetchImageRateLimits( |
|
|
export async function fetchImageRateLimits( |
|
|
apiServer: string, |
|
|
apiServer: string, |
|
|
axios: Axios, |
|
|
axios: Axios, |
|
|
identity: IIdentifier, |
|
|
did: string, |
|
|
) { |
|
|
) { |
|
|
const url = DEFAULT_IMAGE_API_SERVER + "/image-limits"; |
|
|
const url = DEFAULT_IMAGE_API_SERVER + "/image-limits"; |
|
|
const headers = await getHeaders(identity); |
|
|
const headers = await getHeaders(did); |
|
|
return await axios.get(url, { headers } as AxiosRequestConfig); |
|
|
return await axios.get(url, { headers } as AxiosRequestConfig); |
|
|
} |
|
|
} |
|
|