You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
88 lines
2.9 KiB
88 lines
2.9 KiB
/**
|
|
* Verifiable Credential & DID functions, specifically for EndorserSearch.org tools
|
|
*
|
|
* The goal is to make this folder similar across projects, then move it to a library.
|
|
* Other projects: endorser-ch, crowd-funder-for-time-pwa
|
|
*
|
|
*/
|
|
|
|
import base64url from "base64url";
|
|
import didJwt from "did-jwt";
|
|
import {Resolver} from "did-resolver";
|
|
|
|
import ethResolver from "./did-eth-local-resolver";
|
|
import {verifyJwt as peerVerifyJwt} from "./passkeyDidPeer";
|
|
|
|
|
|
export const TEST_BYPASS_ENV_VALUE = "test-local";
|
|
export const ETHR_DID_PREFIX = 'did:ethr:'
|
|
export const PEER_DID_PREFIX = 'did:peer:'
|
|
export const JWT_VERIFY_FAILED_CODE = "JWT_VERIFY_FAILED_CODE"
|
|
export const UNSUPPORTED_DID_METHOD_CODE = "UNSUPPORTED_DID_METHOD"
|
|
|
|
const resolver = new Resolver({
|
|
'ethr': ethResolver.didEthLocalResolver
|
|
});
|
|
|
|
// return Promise of at least { issuer, payload, verified boolean }
|
|
// ... and also if successfully verified by did-jwt (not JWANT): data, doc, signature, signer
|
|
export async function decodeAndVerifyJwt(jwt: string) {
|
|
const pieces = jwt.split('.')
|
|
const header = JSON.parse(base64url.decode(pieces[0]))
|
|
const payload = JSON.parse(base64url.decode(pieces[1]))
|
|
const issuerDid = payload.iss
|
|
if (!issuerDid) {
|
|
return Promise.reject({
|
|
clientError: {
|
|
message: `Missing "iss" field in JWT.`,
|
|
}
|
|
})
|
|
}
|
|
if (issuerDid && issuerDid.startsWith(ETHR_DID_PREFIX) && process.env.NODE_ENV === TEST_BYPASS_ENV_VALUE) {
|
|
// Error of "Cannot read property 'toString' of undefined" usually means the JWT is malformed
|
|
// eg. no "." separators.
|
|
let nowEpoch = Math.floor(new Date().getTime() / 1000)
|
|
if (payload.exp < nowEpoch) {
|
|
console.log("JWT with exp " + payload.exp
|
|
+ " has expired but we're in test mode so we'll use a new time."
|
|
)
|
|
payload.exp = nowEpoch + 100
|
|
}
|
|
return { issuer: issuerDid, payload, verified: true } // other elements will = undefined
|
|
}
|
|
|
|
if (issuerDid.startsWith(ETHR_DID_PREFIX)) {
|
|
try {
|
|
let verified = await didJwt.verifyJWT(jwt, {resolver})
|
|
return verified
|
|
|
|
} catch (e) {
|
|
return Promise.reject({
|
|
clientError: {
|
|
message: `JWT failed verification: ` + e,
|
|
code: JWT_VERIFY_FAILED_CODE
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
if (issuerDid.startsWith(PEER_DID_PREFIX) && header.typ === "JWANT") {
|
|
const { claimPayload, verified } = await peerVerifyJwt(payload, issuerDid, pieces[2])
|
|
return { issuer: issuerDid, payload: claimPayload, verified: verified }
|
|
}
|
|
|
|
if (issuerDid.startsWith(PEER_DID_PREFIX)) {
|
|
return Promise.reject({
|
|
clientError: {
|
|
message: `JWT with a PEER DID currently only supported with typ == JWANT. Contact us us for JWT suport since it should be straightforward.`
|
|
}
|
|
})
|
|
}
|
|
|
|
return Promise.reject({
|
|
clientError: {
|
|
message: `Unsupported DID method ${issuerDid}`,
|
|
code: UNSUPPORTED_DID_METHOD_CODE
|
|
}
|
|
})
|
|
}
|
|
|