@ -1,19 +1,14 @@
import {
import { Axios , AxiosRequestConfig , AxiosResponse } from "axios" ;
Axios ,
AxiosRequestConfig ,
AxiosResponse ,
RawAxiosRequestHeaders ,
} from "axios" ;
import * as didJwt from "did-jwt" ;
import * as didJwt from "did-jwt" ;
import { LRUCache } from "lru-cache" ;
import { LRUCache } from "lru-cache" ;
import * as R from "ramda" ;
import * as R from "ramda" ;
import { IIdentifier } from "@veramo/core" ;
import { DEFAULT_IMAGE_API_SERVER } from "@/constants/app" ;
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 +155,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 +448,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 ( d id) {
const token = await accessToken ( identity ) ;
const token = await accessToken ( d id) ;
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 +482,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 ) {
@ -518,6 +515,9 @@ export async function setPlanInCache(
planCache . set ( handleId , planSummary ) ;
planCache . set ( handleId , planSummary ) ;
}
}
/ * *
* Construct GiveAction VC for submission to server
* /
export function constructGive (
export function constructGive (
fromDid? : string | null ,
fromDid? : string | null ,
toDid? : string ,
toDid? : string ,
@ -572,7 +572,7 @@ export function constructGive(
export async function createAndSubmitGive (
export async function createAndSubmitGive (
axios : Axios ,
axios : Axios ,
apiServer : string ,
apiServer : string ,
identity : IIdentifier ,
issuerDid : string ,
fromDid? : string | null ,
fromDid? : string | null ,
toDid? : string ,
toDid? : string ,
description? : string ,
description? : string ,
@ -596,7 +596,7 @@ export async function createAndSubmitGive(
) ;
) ;
return createAndSubmitClaim (
return createAndSubmitClaim (
vcClaim as GenericCredWrapper ,
vcClaim as GenericCredWrapper ,
identity ,
issuerDid ,
apiServer ,
apiServer ,
axios ,
axios ,
) ;
) ;
@ -614,7 +614,7 @@ export async function createAndSubmitGive(
export async function createAndSubmitOffer (
export async function createAndSubmitOffer (
axios : Axios ,
axios : Axios ,
apiServer : string ,
apiServer : string ,
identity : IIdentifier ,
issuerDid : string ,
description? : string ,
description? : string ,
amount? : number ,
amount? : number ,
unitCode? : string ,
unitCode? : string ,
@ -625,7 +625,7 @@ export async function createAndSubmitOffer(
const vcClaim : OfferVerifiableCredential = {
const vcClaim : OfferVerifiableCredential = {
"@context" : SCHEMA_ORG_CONTEXT ,
"@context" : SCHEMA_ORG_CONTEXT ,
"@type" : "Offer" ,
"@type" : "Offer" ,
offeredBy : { identifier : identity.d id } ,
offeredBy : { identifier : issuerD id } ,
validThrough : expirationDate || undefined ,
validThrough : expirationDate || undefined ,
} ;
} ;
if ( amount ) {
if ( amount ) {
@ -649,7 +649,7 @@ export async function createAndSubmitOffer(
}
}
return createAndSubmitClaim (
return createAndSubmitClaim (
vcClaim as GenericCredWrapper ,
vcClaim as GenericCredWrapper ,
identity ,
issuerDid ,
apiServer ,
apiServer ,
axios ,
axios ,
) ;
) ;
@ -657,7 +657,7 @@ export async function createAndSubmitOffer(
// similar logic is found in endorser-mobile
// similar logic is found in endorser-mobile
export const createAndSubmitConfirmation = async (
export const createAndSubmitConfirmation = async (
identifier : IIdentifier ,
issuerDid : string ,
claim : GenericVerifiableCredential ,
claim : GenericVerifiableCredential ,
lastClaimId : string , // used to set the lastClaimId
lastClaimId : string , // used to set the lastClaimId
handleId : string | undefined ,
handleId : string | undefined ,
@ -674,12 +674,12 @@ export const createAndSubmitConfirmation = async (
"@type" : "AgreeAction" ,
"@type" : "AgreeAction" ,
object : goodClaim ,
object : goodClaim ,
} ;
} ;
return createAndSubmitClaim ( confirmationClaim , identifier , apiServer , axios ) ;
return createAndSubmitClaim ( confirmationClaim , issuerDid , apiServer , axios ) ;
} ;
} ;
export async function createAndSubmitClaim (
export async function createAndSubmitClaim (
vcClaim : GenericVerifiableCredential ,
vcClaim : GenericVerifiableCredential ,
identity : IIdentifier ,
issuerDid : string ,
apiServer : string ,
apiServer : string ,
axios : Axios ,
axios : Axios ,
) : Promise < CreateAndSubmitClaimResult > {
) : Promise < CreateAndSubmitClaimResult > {
@ -692,34 +692,15 @@ export async function createAndSubmitClaim(
} ,
} ,
} ;
} ;
// Create a signature using private key of identity
const vcJwt : string = await createEndorserJwt ( issuerDid , vcPayload ) ;
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 ,
} ) ;
// Make the xhr request payload
// Make the xhr request payload
const payload = JSON . stringify ( { jwtEncoded : vcJwt } ) ;
const payload = JSON . stringify ( { jwtEncoded : vcJwt } ) ;
const url = ` ${ apiServer } /api/v2/claim ` ;
const url = ` ${ apiServer } /api/v2/claim ` ;
const token = await accessToken ( identity ) ;
const response = await axios . post ( url , payload , {
const response = await axios . post ( url , payload , {
headers : {
headers : {
"Content-Type" : "application/json" ,
"Content-Type" : "application/json" ,
Authorization : ` Bearer ${ token } ` ,
} ,
} ,
} ) ;
} ) ;
@ -944,18 +925,49 @@ export const bvcMeetingJoinClaim = (did: string, startTime: string) => {
} ;
} ;
} ;
} ;
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 : issuerDid ,
signer : signer ,
} ) ;
} else if ( account ? . passkeyCredIdHex ) {
return createDidPeerJwt ( issuerDid , account . passkeyCredIdHex , payload ) ;
} else {
throw new Error ( "No identity data found to sign for DID " + issuerDid ) ;
}
}
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 : activeD id } ,
object : SERVICE_ID ,
object : SERVICE_ID ,
participant : { identifier : contact.did } ,
participant : { identifier : contact.did } ,
} ;
} ;
@ -968,26 +980,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 +1013,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 {
@ -1046,16 +1042,16 @@ export async function setVisibilityUtil(
*
*
* @param apiServer endorser server URL string
* @param apiServer endorser server URL string
* @param axios Axios instance
* @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 .
* @returns { Promise < AxiosResponse > } The Axios response object .
* /
* /
export async function fetchEndorserRateLimits (
export async function fetchEndorserRateLimits (
apiServer : string ,
apiServer : string ,
axios : Axios ,
axios : Axios ,
identity : IIdentifier ,
issuerDid : string ,
) {
) {
const url = ` ${ apiServer } /api/report/rateLimits ` ;
const url = ` ${ apiServer } /api/report/rateLimits ` ;
const headers = await getHeaders ( identity ) ;
const headers = await getHeaders ( issuerDid ) ;
return await axios . get ( url , { headers } as AxiosRequestConfig ) ;
return await axios . get ( url , { headers } as AxiosRequestConfig ) ;
}
}
@ -1064,15 +1060,11 @@ export async function fetchEndorserRateLimits(
*
*
* @param apiServer image server URL string
* @param apiServer image server URL string
* @param axios Axios instance
* @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 .
* @returns { Promise < AxiosResponse > } The Axios response object .
* /
* /
export async function fetchImageRateLimits (
export async function fetchImageRateLimits ( axios : Axios , issuerDid : string ) {
apiServer : string ,
axios : Axios ,
identity : IIdentifier ,
) {
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 ( issuerDid ) ;
return await axios . get ( url , { headers } as AxiosRequestConfig ) ;
return await axios . get ( url , { headers } as AxiosRequestConfig ) ;
}
}