did-jwt-vc
Advanced tools
Comparing version 2.1.3 to 2.1.4
@@ -0,1 +1,8 @@ | ||
## [2.1.4](https://github.com/decentralized-identity/did-jwt-vc/compare/2.1.3...2.1.4) (2021-07-13) | ||
### Bug Fixes | ||
* allow VPs without VCs ([#83](https://github.com/decentralized-identity/did-jwt-vc/issues/83)) ([e534b4d](https://github.com/decentralized-identity/did-jwt-vc/commit/e534b4dc1747da1071d489c2301e18e28f24f56b)) | ||
## [2.1.3](https://github.com/decentralized-identity/did-jwt-vc/compare/2.1.2...2.1.3) (2021-06-16) | ||
@@ -2,0 +9,0 @@ |
@@ -0,0 +0,0 @@ export declare const JWT_ALG = "ES256K"; |
import { VerifiableCredential, JWT, JwtPresentationPayload, JwtCredentialPayload, CredentialPayload, W3CCredential, Verifiable, PresentationPayload, W3CPresentation } from './types'; | ||
export declare function asArray(input: any): any[]; | ||
export declare function asArray(arg: any | any[]): any[]; | ||
export declare function notEmpty<TValue>(value: TValue | null | undefined): value is TValue; | ||
export declare function isLegacyAttestationFormat(payload: any): boolean; | ||
export declare function attestationToVcFormat(payload: any): JwtCredentialPayload; | ||
export declare function isLegacyAttestationFormat(payload: Record<string, any>): boolean; | ||
export declare function attestationToVcFormat(payload: Record<string, any>): JwtCredentialPayload; | ||
/** | ||
@@ -16,3 +16,3 @@ * Normalizes a credential payload into an unambiguous W3C credential data type | ||
*/ | ||
declare type DeepPartial<T> = T extends object ? { | ||
declare type DeepPartial<T> = T extends Record<string, unknown> ? { | ||
[K in keyof T]?: DeepPartial<T[K]>; | ||
@@ -19,0 +19,0 @@ } : T; |
import { Resolvable } from 'did-resolver'; | ||
import { JwtCredentialPayload, Issuer, JwtPresentationPayload, JWT, VerifiablePresentation, VerifiableCredential, CredentialPayload, PresentationPayload, Verifiable, W3CCredential, W3CPresentation, VerifiedCredential, VerifiedPresentation, VerifyPresentationOptions, CreatePresentationOptions, CreateCredentialOptions, VerifyCredentialOptions } from './types'; | ||
import { transformCredentialInput, transformPresentationInput, normalizeCredential, normalizePresentation } from './converters'; | ||
export { Issuer, CredentialPayload, PresentationPayload, JwtCredentialPayload, JwtPresentationPayload, VerifiableCredential, VerifiablePresentation, VerifiedCredential, VerifiedPresentation, Verifiable, W3CCredential, W3CPresentation, transformCredentialInput, transformPresentationInput, normalizeCredential, normalizePresentation }; | ||
export { Issuer, CredentialPayload, PresentationPayload, JwtCredentialPayload, JwtPresentationPayload, VerifiableCredential, VerifiablePresentation, VerifiedCredential, VerifiedPresentation, Verifiable, W3CCredential, W3CPresentation, transformCredentialInput, transformPresentationInput, normalizeCredential, normalizePresentation, }; | ||
/** | ||
@@ -6,0 +6,0 @@ * Creates a VerifiableCredential given a `CredentialPayload` or `JwtCredentialPayload` and an `Issuer`. |
336
lib/index.js
@@ -1,334 +0,2 @@ | ||
"use strict"; | ||
var __assign = (this && this.__assign) || function () { | ||
__assign = Object.assign || function(t) { | ||
for (var s, i = 1, n = arguments.length; i < n; i++) { | ||
s = arguments[i]; | ||
for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p)) | ||
t[p] = s[p]; | ||
} | ||
return t; | ||
}; | ||
return __assign.apply(this, arguments); | ||
}; | ||
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) { | ||
if (k2 === undefined) k2 = k; | ||
Object.defineProperty(o, k2, { enumerable: true, get: function() { return m[k]; } }); | ||
}) : (function(o, m, k, k2) { | ||
if (k2 === undefined) k2 = k; | ||
o[k2] = m[k]; | ||
})); | ||
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) { | ||
Object.defineProperty(o, "default", { enumerable: true, value: v }); | ||
}) : function(o, v) { | ||
o["default"] = v; | ||
}); | ||
var __importStar = (this && this.__importStar) || function (mod) { | ||
if (mod && mod.__esModule) return mod; | ||
var result = {}; | ||
if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k); | ||
__setModuleDefault(result, mod); | ||
return result; | ||
}; | ||
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { | ||
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } | ||
return new (P || (P = Promise))(function (resolve, reject) { | ||
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } | ||
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } | ||
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } | ||
step((generator = generator.apply(thisArg, _arguments || [])).next()); | ||
}); | ||
}; | ||
var __generator = (this && this.__generator) || function (thisArg, body) { | ||
var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g; | ||
return g = { next: verb(0), "throw": verb(1), "return": verb(2) }, typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g; | ||
function verb(n) { return function (v) { return step([n, v]); }; } | ||
function step(op) { | ||
if (f) throw new TypeError("Generator is already executing."); | ||
while (_) try { | ||
if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t; | ||
if (y = 0, t) op = [op[0] & 2, t.value]; | ||
switch (op[0]) { | ||
case 0: case 1: t = op; break; | ||
case 4: _.label++; return { value: op[1], done: false }; | ||
case 5: _.label++; y = op[1]; op = [0]; continue; | ||
case 7: op = _.ops.pop(); _.trys.pop(); continue; | ||
default: | ||
if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; } | ||
if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; } | ||
if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; } | ||
if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; } | ||
if (t[2]) _.ops.pop(); | ||
_.trys.pop(); continue; | ||
} | ||
op = body.call(thisArg, _); | ||
} catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; } | ||
if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true }; | ||
} | ||
}; | ||
var __read = (this && this.__read) || function (o, n) { | ||
var m = typeof Symbol === "function" && o[Symbol.iterator]; | ||
if (!m) return o; | ||
var i = m.call(o), r, ar = [], e; | ||
try { | ||
while ((n === void 0 || n-- > 0) && !(r = i.next()).done) ar.push(r.value); | ||
} | ||
catch (error) { e = { error: error }; } | ||
finally { | ||
try { | ||
if (r && !r.done && (m = i["return"])) m.call(i); | ||
} | ||
finally { if (e) throw e.error; } | ||
} | ||
return ar; | ||
}; | ||
var __spreadArray = (this && this.__spreadArray) || function (to, from) { | ||
for (var i = 0, il = from.length, j = to.length; i < il; i++, j++) | ||
to[j] = from[i]; | ||
return to; | ||
}; | ||
var __values = (this && this.__values) || function(o) { | ||
var s = typeof Symbol === "function" && Symbol.iterator, m = s && o[s], i = 0; | ||
if (m) return m.call(o); | ||
if (o && typeof o.length === "number") return { | ||
next: function () { | ||
if (o && i >= o.length) o = void 0; | ||
return { value: o && o[i++], done: !o }; | ||
} | ||
}; | ||
throw new TypeError(s ? "Object is not iterable." : "Symbol.iterator is not defined."); | ||
}; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
exports.verifyPresentation = exports.verifyPresentationPayloadOptions = exports.verifyCredential = exports.validatePresentationPayload = exports.validateJwtPresentationPayload = exports.validateCredentialPayload = exports.validateJwtCredentialPayload = exports.createVerifiablePresentationJwt = exports.createVerifiableCredentialJwt = exports.normalizePresentation = exports.normalizeCredential = exports.transformPresentationInput = exports.transformCredentialInput = void 0; | ||
var did_jwt_1 = require("did-jwt"); | ||
var constants_1 = require("./constants"); | ||
var validators = __importStar(require("./validators")); | ||
var converters_1 = require("./converters"); | ||
Object.defineProperty(exports, "transformCredentialInput", { enumerable: true, get: function () { return converters_1.transformCredentialInput; } }); | ||
Object.defineProperty(exports, "transformPresentationInput", { enumerable: true, get: function () { return converters_1.transformPresentationInput; } }); | ||
Object.defineProperty(exports, "normalizeCredential", { enumerable: true, get: function () { return converters_1.normalizeCredential; } }); | ||
Object.defineProperty(exports, "normalizePresentation", { enumerable: true, get: function () { return converters_1.normalizePresentation; } }); | ||
/** | ||
* Creates a VerifiableCredential given a `CredentialPayload` or `JwtCredentialPayload` and an `Issuer`. | ||
* | ||
* This method transforms the payload into the [JWT encoding](https://www.w3.org/TR/vc-data-model/#jwt-encoding) | ||
* described in the [W3C VC spec](https://www.w3.org/TR/vc-data-model) and then validated to conform to the minimum spec | ||
* required spec. | ||
* | ||
* The `issuer` is then used to assign an algorithm, override the `iss` field of the payload and then sign the JWT. | ||
* | ||
* @param payload `CredentialPayload` or `JwtCredentialPayload` | ||
* @param issuer `Issuer` the DID, signer and algorithm that will sign the token | ||
* @return a `Promise` that resolves to the JWT encoded verifiable credential or rejects with `TypeError` if the | ||
* `payload` is not W3C compliant | ||
*/ | ||
function createVerifiableCredentialJwt(payload, issuer, options) { | ||
var _a; | ||
if (options === void 0) { options = {}; } | ||
return __awaiter(this, void 0, void 0, function () { | ||
var parsedPayload; | ||
return __generator(this, function (_b) { | ||
parsedPayload = __assign({ iat: undefined }, converters_1.transformCredentialInput(payload, options.removeOriginalFields)); | ||
validateJwtCredentialPayload(parsedPayload); | ||
return [2 /*return*/, did_jwt_1.createJWT(parsedPayload, { | ||
issuer: issuer.did || parsedPayload.iss, | ||
signer: issuer.signer | ||
}, __assign(__assign({}, options.header), { alg: issuer.alg || ((_a = options.header) === null || _a === void 0 ? void 0 : _a.alg) || constants_1.JWT_ALG }))]; | ||
}); | ||
}); | ||
} | ||
exports.createVerifiableCredentialJwt = createVerifiableCredentialJwt; | ||
/** | ||
* Creates a VerifiablePresentation JWT given a `PresentationPayload` or `JwtPresentationPayload` and an `Issuer`. | ||
* | ||
* This method transforms the payload into the [JWT encoding](https://www.w3.org/TR/vc-data-model/#jwt-encoding) | ||
* described in the [W3C VC spec](https://www.w3.org/TR/vc-data-model) and then validated to conform to the minimum spec | ||
* required spec. | ||
* | ||
* The `holder` is then used to assign an algorithm, override the `iss` field of the payload and then sign the JWT. | ||
* | ||
* @param payload `PresentationPayload` or `JwtPresentationPayload` | ||
* @param holder `Issuer` of the Presentation JWT (holder of the VC), signer and algorithm that will sign the token | ||
* @param options `CreatePresentationOptions` allows to pass additional values to the resulting JWT payload | ||
* @return a `Promise` that resolves to the JWT encoded verifiable presentation or rejects with `TypeError` if the | ||
* `payload` is not W3C compliant | ||
*/ | ||
function createVerifiablePresentationJwt(payload, holder, options) { | ||
var _a; | ||
if (options === void 0) { options = {}; } | ||
return __awaiter(this, void 0, void 0, function () { | ||
var parsedPayload, audience; | ||
return __generator(this, function (_b) { | ||
parsedPayload = __assign({ iat: undefined }, converters_1.transformPresentationInput(payload, options === null || options === void 0 ? void 0 : options.removeOriginalFields)); | ||
// add challenge to nonce | ||
if (options.challenge && Object.getOwnPropertyNames(parsedPayload).indexOf('nonce') === -1) { | ||
parsedPayload.nonce = options.challenge; | ||
} | ||
// add domain to audience. | ||
if (options.domain) { | ||
audience = __spreadArray(__spreadArray([], __read(converters_1.asArray(options.domain))), __read(converters_1.asArray(parsedPayload.aud))).filter(converters_1.notEmpty); | ||
parsedPayload.aud = __spreadArray([], __read(new Set(audience))); | ||
} | ||
validateJwtPresentationPayload(parsedPayload); | ||
return [2 /*return*/, did_jwt_1.createJWT(parsedPayload, { | ||
issuer: holder.did || parsedPayload.iss, | ||
signer: holder.signer | ||
}, __assign(__assign({}, options.header), { alg: holder.alg || ((_a = options.header) === null || _a === void 0 ? void 0 : _a.alg) || constants_1.JWT_ALG }))]; | ||
}); | ||
}); | ||
} | ||
exports.createVerifiablePresentationJwt = createVerifiablePresentationJwt; | ||
function validateJwtCredentialPayload(payload) { | ||
validators.validateContext(payload.vc['@context']); | ||
validators.validateVcType(payload.vc.type); | ||
validators.validateCredentialSubject(payload.vc.credentialSubject); | ||
if (payload.nbf) | ||
validators.validateTimestamp(payload.nbf); | ||
if (payload.exp) | ||
validators.validateTimestamp(payload.exp); | ||
} | ||
exports.validateJwtCredentialPayload = validateJwtCredentialPayload; | ||
function validateCredentialPayload(payload) { | ||
validators.validateContext(payload['@context']); | ||
validators.validateVcType(payload.type); | ||
validators.validateCredentialSubject(payload.credentialSubject); | ||
if (payload.issuanceDate) | ||
validators.validateTimestamp(payload.issuanceDate); | ||
if (payload.expirationDate) | ||
validators.validateTimestamp(payload.expirationDate); | ||
} | ||
exports.validateCredentialPayload = validateCredentialPayload; | ||
function validateJwtPresentationPayload(payload) { | ||
var e_1, _a; | ||
validators.validateContext(payload.vp['@context']); | ||
validators.validateVpType(payload.vp.type); | ||
if (payload.vp.verifiableCredential.length < 1) { | ||
throw new TypeError('vp.verifiableCredential must not be empty'); | ||
} | ||
try { | ||
for (var _b = __values(converters_1.asArray(payload.vp.verifiableCredential)), _c = _b.next(); !_c.done; _c = _b.next()) { | ||
var vc = _c.value; | ||
if (typeof vc === 'string') { | ||
validators.validateJwtFormat(vc); | ||
} | ||
else { | ||
validateCredentialPayload(vc); | ||
} | ||
} | ||
} | ||
catch (e_1_1) { e_1 = { error: e_1_1 }; } | ||
finally { | ||
try { | ||
if (_c && !_c.done && (_a = _b.return)) _a.call(_b); | ||
} | ||
finally { if (e_1) throw e_1.error; } | ||
} | ||
if (payload.exp) | ||
validators.validateTimestamp(payload.exp); | ||
} | ||
exports.validateJwtPresentationPayload = validateJwtPresentationPayload; | ||
function validatePresentationPayload(payload) { | ||
var e_2, _a; | ||
validators.validateContext(payload['@context']); | ||
validators.validateVpType(payload.type); | ||
if (payload.verifiableCredential.length < 1) { | ||
throw new TypeError('vp.verifiableCredential must not be empty'); | ||
} | ||
try { | ||
for (var _b = __values(payload.verifiableCredential), _c = _b.next(); !_c.done; _c = _b.next()) { | ||
var vc = _c.value; | ||
if (typeof vc === 'string') { | ||
validators.validateJwtFormat(vc); | ||
} | ||
else { | ||
validateCredentialPayload(vc); | ||
} | ||
} | ||
} | ||
catch (e_2_1) { e_2 = { error: e_2_1 }; } | ||
finally { | ||
try { | ||
if (_c && !_c.done && (_a = _b.return)) _a.call(_b); | ||
} | ||
finally { if (e_2) throw e_2.error; } | ||
} | ||
if (payload.expirationDate) | ||
validators.validateTimestamp(payload.expirationDate); | ||
} | ||
exports.validatePresentationPayload = validatePresentationPayload; | ||
/** | ||
* Verifies and validates a VerifiableCredential that is encoded as a JWT according to the W3C spec. | ||
* | ||
* @return a `Promise` that resolves to a `VerifiedCredential` or rejects with `TypeError` if the input is not | ||
* W3C compliant | ||
* @param vc the credential to be verified. Currently only the JWT encoding is supported by this library | ||
* @param resolver a configured `Resolver` (or an implementation of `Resolvable`) that can provide the DID document of the JWT issuer | ||
*/ | ||
function verifyCredential(vc, resolver, options) { | ||
if (options === void 0) { options = {}; } | ||
return __awaiter(this, void 0, void 0, function () { | ||
var verified; | ||
return __generator(this, function (_a) { | ||
switch (_a.label) { | ||
case 0: return [4 /*yield*/, did_jwt_1.verifyJWT(vc, __assign({ resolver: resolver }, options))]; | ||
case 1: | ||
verified = _a.sent(); | ||
verified.verifiableCredential = converters_1.normalizeCredential(verified.jwt, options === null || options === void 0 ? void 0 : options.removeOriginalFields); | ||
validateCredentialPayload(verified.verifiableCredential); | ||
return [2 /*return*/, verified]; | ||
} | ||
}); | ||
}); | ||
} | ||
exports.verifyCredential = verifyCredential; | ||
/** | ||
* Verifies that the given JwtPresentationPayload contains the appropriate options from VerifyPresentationOptions | ||
* | ||
* @param payload the JwtPresentationPayload to verify against | ||
* @param options the VerifyPresentationOptions that contain the optional values to verify. | ||
* @throws {Error} If VerifyPresentationOptions are not satisfied | ||
*/ | ||
function verifyPresentationPayloadOptions(payload, options) { | ||
if (options.challenge && options.challenge !== payload.nonce) { | ||
throw new Error("Presentation does not contain the mandatory challenge (JWT: nonce) for : " + options.challenge); | ||
} | ||
if (options.domain) { | ||
// aud might be array | ||
var matchedAudience = void 0; | ||
if (payload.aud) { | ||
var audArray = Array.isArray(payload.aud) ? payload.aud : [payload.aud]; | ||
matchedAudience = audArray.find(function (item) { return options.domain === item; }); | ||
} | ||
if (typeof matchedAudience === 'undefined') { | ||
throw new Error("Presentation does not contain the mandatory domain (JWT: aud) for : " + options.domain); | ||
} | ||
} | ||
} | ||
exports.verifyPresentationPayloadOptions = verifyPresentationPayloadOptions; | ||
/** | ||
* Verifies and validates a VerifiablePresentation that is encoded as a JWT according to the W3C spec. | ||
* | ||
* @return a `Promise` that resolves to a `VerifiedPresentation` or rejects with `TypeError` if the input is | ||
* not W3C compliant or the VerifyPresentationOptions are not satisfied. | ||
* @param presentation the presentation to be verified. Currently only the JWT encoding is supported by this library | ||
* @param resolver a configured `Resolver` or an implementation of `Resolvable` that can provide the DID document of the JWT issuer (presentation holder) | ||
* @param options optional verification options that need to be satisfied | ||
*/ | ||
function verifyPresentation(presentation, resolver, options) { | ||
if (options === void 0) { options = {}; } | ||
return __awaiter(this, void 0, void 0, function () { | ||
var verified; | ||
return __generator(this, function (_a) { | ||
switch (_a.label) { | ||
case 0: return [4 /*yield*/, did_jwt_1.verifyJWT(presentation, __assign({ resolver: resolver }, options))]; | ||
case 1: | ||
verified = _a.sent(); | ||
verifyPresentationPayloadOptions(verified.payload, options); | ||
verified.verifiablePresentation = converters_1.normalizePresentation(verified.jwt, options === null || options === void 0 ? void 0 : options.removeOriginalFields); | ||
validatePresentationPayload(verified.verifiablePresentation); | ||
return [2 /*return*/, verified]; | ||
} | ||
}); | ||
}); | ||
} | ||
exports.verifyPresentation = verifyPresentation; | ||
//# sourceMappingURL=index.js.map | ||
var e=require("did-jwt");const t=/^[A-Za-z0-9-_=]+\.[A-Za-z0-9-_=]+\.?[A-Za-z0-9-_.+/=]*$/,r="https://www.w3.org/2018/credentials/v1";function n(e){return Array.isArray(e)?e:[e]}function i(e){return Array.isArray(e)?e.map(e=>i(e)):e instanceof Date?new Date(e.getTime()):e&&"object"==typeof e?Object.getOwnPropertyNames(e).reduce((t,r)=>(Object.defineProperty(t,r,Object.getOwnPropertyDescriptor(e,r)),t[r]=i(e[r]),t),Object.create(Object.getPrototypeOf(e))):e}function o(e){return null!=e}function a(e,t=!0){var a,l,c,s,d,f,u;let p=i(e);var v,y,b;"object"==typeof(v=e)&&v.sub&&v.iss&&v.claim&&v.iat&&(p=function(e){const{iat:t,nbf:n,claim:i,vc:o,...a}=e,l={...a,nbf:n||t,vc:{"@context":[r],type:["VerifiableCredential"],credentialSubject:i}};return o&&(e.issVc=o),l}(e)),p.credentialSubject={...e.credentialSubject,...null==(a=e.vc)?void 0:a.credentialSubject},!e.sub||null!=(l=e.credentialSubject)&&l.id||!p.credentialSubject||(p.credentialSubject.id=e.sub,t&&delete p.sub),t&&(null==(y=p.vc)||delete y.credentialSubject),void 0!==e.issuer&&"object"!=typeof e.issuer||(p.issuer=function(e){if("object"!=typeof e)return e;const t={...e};return Object.keys(t).forEach(e=>void 0===t[e]&&delete t[e]),t}({id:e.iss,...e.issuer}),!t||null!=(b=e.issuer)&&b.id||delete p.iss),!e.id&&e.jti&&(p.id=p.id||p.jti,t&&delete p.jti);const x=[...n(p.type),...n(null==(c=p.vc)?void 0:c.type)].filter(o);var w,j,O,m;p.type=[...new Set(x)],t&&(null==(w=p.vc)||delete w.type),p.evidence=null==(s=e.vc)?void 0:s.evidence,t&&(null==(j=p.vc)||delete j.evidence),p.credentialStatus=null==(d=e.vc)?void 0:d.credentialStatus,t&&(null==(O=p.vc)||delete O.credentialStatus),p.termsOfUse=null==(f=e.vc)?void 0:f.termsOfUse,t&&(null==(m=p.vc)||delete m.termsOfUse);const g=[...n(e.context),...n(e["@context"]),...n(null==(u=e.vc)?void 0:u["@context"])].filter(o);var h;return p["@context"]=[...new Set(g)],t&&(delete p.context,null==(h=p.vc)||delete h["@context"]),e.issuanceDate||!e.iat&&!e.nbf||(p.issuanceDate=new Date(1e3*(e.nbf||e.iat)).toISOString(),t&&(e.nbf?delete p.nbf:delete p.iat)),!e.expirationDate&&e.exp&&(p.expirationDate=new Date(1e3*e.exp).toISOString(),t&&delete p.exp),t&&p.vc&&0===Object.keys(p.vc).length&&delete p.vc,p}function l(t,r=!0){let n;try{n=e.decodeJWT(t)}catch(e){throw new TypeError("unknown credential format")}return{...a(n.payload,r),proof:{type:"JwtProof2020",jwt:t}}}function c(e,r=!0){var n;if("string"==typeof e){if(t.test(e))return l(e,r);{let t;try{t=JSON.parse(e)}catch(e){throw new TypeError("unknown credential format")}return c(t,r)}}return null!=(n=e.proof)&&n.jwt?i({...l(e.proof.jwt,r),proof:e.proof}):{proof:{},...a(e,r)}}function s(e,t=!0){var r,a,l;if(Array.isArray(e.credentialSubject))throw Error("credentialSubject of type array not supported");const c=i({vc:{...e.vc},...e});c.vc=c.vc;const s={...e.credentialSubject,...null==(r=e.vc)?void 0:r.credentialSubject};var d;e.sub||(c.sub=null==(d=e.credentialSubject)?void 0:d.id,t&&delete s.id);const f=[...n(e.context),...n(e["@context"]),...n(null==(a=e.vc)?void 0:a["@context"])].filter(o);c.vc["@context"]=[...new Set(f)],t&&(delete c.context,delete c["@context"]);const u=[...n(e.type),...n(null==(l=e.vc)?void 0:l.type)].filter(o);if(c.vc.type=[...new Set(u)],t&&delete c.type,e.id&&-1===Object.getOwnPropertyNames(e).indexOf("jti")&&(c.jti=e.id,t&&delete c.id),e.issuanceDate&&-1===Object.getOwnPropertyNames(e).indexOf("nbf")){const r=Date.parse(e.issuanceDate);isNaN(r)||(c.nbf=Math.floor(r/1e3),t&&delete c.issuanceDate)}if(e.expirationDate&&-1===Object.getOwnPropertyNames(e).indexOf("exp")){const r=Date.parse(e.expirationDate);isNaN(r)||(c.exp=Math.floor(r/1e3),t&&delete c.expirationDate)}var p;e.issuer&&-1===Object.getOwnPropertyNames(e).indexOf("iss")&&("object"==typeof e.issuer?(c.iss=null==(p=e.issuer)?void 0:p.id,t&&(delete c.issuer.id,0===Object.keys(c.issuer).length&&delete c.issuer)):"string"==typeof e.issuer&&(c.iss=e.iss||""+e.issuer,t&&delete c.issuer)),c.vc.credentialSubject=s,t&&delete c.credentialSubject;const v=["evidence","termsOfUse","refreshService","credentialSchema","credentialStatus"];for(const r of v)e[r]&&(c.vc[r]||(c.vc[r]=e[r]),t&&delete c[r]);return c}function d(e,t=!0){var r,a,l;const s=i(e);var d;s.verifiableCredential=[...n(e.verifiableCredential),...n(null==(r=e.vp)?void 0:r.verifiableCredential)].filter(o),s.verifiableCredential=s.verifiableCredential.map(e=>c(e,t)),t&&(null==(d=s.vp)||delete d.verifiableCredential),e.iss&&!e.holder&&(s.holder=e.iss,t&&delete s.iss),e.aud&&(s.verifier=[...n(e.verifier),...n(e.aud)].filter(o),s.verifier=[...new Set(s.verifier)],t&&delete s.aud),e.jti&&-1===Object.getOwnPropertyNames(e).indexOf("id")&&(s.id=e.id||e.jti,t&&delete s.jti);const f=[...n(e.type),...n(null==(a=e.vp)?void 0:a.type)].filter(o);var u;s.type=[...new Set(f)],t&&(null==(u=s.vp)||delete u.type);const p=[...n(e.context),...n(e["@context"]),...n(null==(l=e.vp)?void 0:l["@context"])].filter(o);var v;return s["@context"]=[...new Set(p)],t&&(delete s.context,null==(v=s.vp)||delete v["@context"]),e.issuanceDate||!e.iat&&!e.nbf||(s.issuanceDate=new Date(1e3*(e.nbf||e.iat)).toISOString(),t&&(e.nbf?delete s.nbf:delete s.iat)),!e.expirationDate&&e.exp&&(s.expirationDate=new Date(1e3*e.exp).toISOString(),t&&delete s.exp),s.vp&&0===Object.keys(s.vp).length&&t&&delete s.vp,s}function f(t,r=!0){let n;try{n=e.decodeJWT(t)}catch(e){throw new TypeError("unknown presentation format")}return{...d(n.payload,r),proof:{type:"JwtProof2020",jwt:t}}}function u(e,r=!0){var n;if("string"==typeof e){if(t.test(e))return f(e,r);{let t;try{t=JSON.parse(e)}catch(e){throw new TypeError("unknown presentation format")}return u(t,r)}}return null!=(n=e.proof)&&n.jwt?{...f(e.proof.jwt,r),proof:e.proof}:{proof:{},...d(e,r)}}function p(e,t=!0){var r,a,l;const c=i({vp:{...e.vp},...e});c.vp=c.vp;const s=[...n(e.context),...n(e["@context"]),...n(null==(r=e.vp)?void 0:r["@context"])].filter(o);c.vp["@context"]=[...new Set(s)],t&&(delete c.context,delete c["@context"]);const d=[...n(e.type),...n(null==(a=e.vp)?void 0:a.type)].filter(o);if(c.vp.type=[...new Set(d)],t&&delete c.type,e.id&&-1===Object.getOwnPropertyNames(e).indexOf("jti")&&(c.jti=e.id,t&&delete c.id),e.issuanceDate&&-1===Object.getOwnPropertyNames(e).indexOf("nbf")){const r=Date.parse(e.issuanceDate);isNaN(r)||(c.nbf=Math.floor(r/1e3),t&&delete c.issuanceDate)}if(e.expirationDate&&-1===Object.getOwnPropertyNames(e).indexOf("exp")){const r=Date.parse(e.expirationDate);isNaN(r)||(c.exp=Math.floor(r/1e3),t&&delete c.expirationDate)}var f;if((c.verifiableCredential||null!=(l=c.vp)&&l.verifiableCredential)&&(c.vp.verifiableCredential=[...n(c.verifiableCredential),...n(null==(f=c.vp)?void 0:f.verifiableCredential)].filter(o).map(e=>{var t;return"object"==typeof e&&null!=(t=e.proof)&&t.jwt?e.proof.jwt:e})),t&&delete c.verifiableCredential,e.holder&&-1===Object.getOwnPropertyNames(e).indexOf("iss")&&"string"==typeof e.holder&&(c.iss=e.holder,t&&delete c.holder),e.verifier){const r=[...n(e.verifier),...n(e.aud)].filter(o);c.aud=[...new Set(r)],t&&delete c.verifier}return c}function v(e){if("string"==typeof e&&!e.match(t))throw new TypeError(`"${e}" is not a valid JWT format`)}function y(e){if("number"==typeof e){if(!(Number.isInteger(e)&&e<1e11))throw new TypeError(`"${e}" is not a unix timestamp in seconds`)}else if("string"==typeof e)y(Math.floor(new Date(e).valueOf()/1e3));else if(!(t=e)||isNaN(t)||"[object Date]"!==Object.prototype.toString.call(t))throw new TypeError(`"${e}" is not a valid time`);var t}function b(e){const t=n(e);if(t.length<1||-1===t.indexOf(r))throw new TypeError(`@context is missing default context "${r}"`)}function x(e){const t=n(e);if(t.length<1||-1===t.indexOf("VerifiableCredential"))throw new TypeError('type is missing default "VerifiableCredential"')}function w(e){const t=n(e);if(t.length<1||-1===t.indexOf("VerifiablePresentation"))throw new TypeError('type is missing default "VerifiablePresentation"')}function j(e){if(0===Object.keys(e).length)throw new TypeError("credentialSubject must not be empty")}function O(e){b(e.vc["@context"]),x(e.vc.type),j(e.vc.credentialSubject),e.nbf&&y(e.nbf),e.exp&&y(e.exp)}function m(e){b(e["@context"]),x(e.type),j(e.credentialSubject),e.issuanceDate&&y(e.issuanceDate),e.expirationDate&&y(e.expirationDate)}function g(e){if(b(e.vp["@context"]),w(e.vp.type),e.vp.verifiableCredential&&e.vp.verifiableCredential.length>=1)for(const t of n(e.vp.verifiableCredential))"string"==typeof t?v(t):m(t);e.exp&&y(e.exp)}function h(e){if(b(e["@context"]),w(e.type),e.verifiableCredential&&e.verifiableCredential.length>=1)for(const t of e.verifiableCredential)"string"==typeof t?v(t):m(t);e.expirationDate&&y(e.expirationDate)}function S(e,t){if(t.challenge&&t.challenge!==e.nonce)throw new Error(`Presentation does not contain the mandatory challenge (JWT: nonce) for : ${t.challenge}`);if(t.domain){let r;if(e.aud&&(r=(Array.isArray(e.aud)?e.aud:[e.aud]).find(e=>t.domain===e)),void 0===r)throw new Error(`Presentation does not contain the mandatory domain (JWT: aud) for : ${t.domain}`)}}exports.createVerifiableCredentialJwt=function(t,r,n={}){try{var i;const o={iat:void 0,...s(t,n.removeOriginalFields)};return O(o),Promise.resolve(e.createJWT(o,{issuer:r.did||o.iss||"",signer:r.signer},{...n.header,alg:r.alg||(null==(i=n.header)?void 0:i.alg)||"ES256K"}))}catch(e){return Promise.reject(e)}},exports.createVerifiablePresentationJwt=function(t,r,i={}){try{var a;const l={iat:void 0,...p(t,null==i?void 0:i.removeOriginalFields)};if(i.challenge&&-1===Object.getOwnPropertyNames(l).indexOf("nonce")&&(l.nonce=i.challenge),i.domain){const e=[...n(i.domain),...n(l.aud)].filter(o);l.aud=[...new Set(e)]}return g(l),Promise.resolve(e.createJWT(l,{issuer:r.did||l.iss||"",signer:r.signer},{...i.header,alg:r.alg||(null==(a=i.header)?void 0:a.alg)||"ES256K"}))}catch(e){return Promise.reject(e)}},exports.normalizeCredential=c,exports.normalizePresentation=u,exports.transformCredentialInput=s,exports.transformPresentationInput=p,exports.validateCredentialPayload=m,exports.validateJwtCredentialPayload=O,exports.validateJwtPresentationPayload=g,exports.validatePresentationPayload=h,exports.verifyCredential=function(t,r,n={}){try{return Promise.resolve(e.verifyJWT(t,{resolver:r,...n})).then(function(e){return e.verifiableCredential=c(e.jwt,null==n?void 0:n.removeOriginalFields),m(e.verifiableCredential),e})}catch(e){return Promise.reject(e)}},exports.verifyPresentation=function(t,r,n={}){try{return Promise.resolve(e.verifyJWT(t,{resolver:r,...n})).then(function(e){return S(e.payload,n),e.verifiablePresentation=u(e.jwt,null==n?void 0:n.removeOriginalFields),h(e.verifiablePresentation),e})}catch(e){return Promise.reject(e)}},exports.verifyPresentationPayloadOptions=S; | ||
//# sourceMappingURL=index.js.map |
import { JwtCredentialSubject, DateType } from './types'; | ||
import { VerifiableCredential } from 'src'; | ||
import { VerifiableCredential } from '.'; | ||
export declare function validateJwtFormat(value: VerifiableCredential): void; | ||
@@ -4,0 +4,0 @@ export declare function validateTimestamp(value: number | DateType): void; |
{ | ||
"name": "did-jwt-vc", | ||
"version": "2.1.3", | ||
"version": "2.1.4", | ||
"description": "Create and verify W3C Verifiable Credentials and Presentations in JWT format", | ||
"main": "lib/index.js", | ||
"source": "src/index.ts", | ||
"types": "lib/index.d.ts", | ||
"main": "./lib/index.js", | ||
"module": "./lib/index.module.js", | ||
"types": "./lib/index.d.ts", | ||
"files": [ | ||
"lib", | ||
"src", | ||
"esm", | ||
"tutorial" | ||
"src" | ||
], | ||
"scripts": { | ||
"test": "jest", | ||
"build": "npm run format && npm test && npm run build:js", | ||
"build:js": "tsc", | ||
"test:ci": "jest --coverage && codecov", | ||
"build:js": "microbundle", | ||
"build": "yarn lint && yarn build:js && yarn test", | ||
"format": "prettier --write \"src/**/*.ts\"", | ||
"lint": "tslint -p tsconfig.json", | ||
"release": "semantic-release --debug", | ||
"test:ci": "jest --coverage && codecov", | ||
"prepare": "npm run build", | ||
"prepublishOnly": "npm test && npm run lint" | ||
"lint": "eslint --ignore-pattern \"src/**/*.test.[jt]s\" \"src/**/*.[jt]s\"", | ||
"prepare": "yarn build", | ||
"prepublishOnly": "yarn test:ci && yarn format && yarn lint", | ||
"release": "semantic-release --debug" | ||
}, | ||
"author": "mi-xu", | ||
"contributors": [ | ||
"Mircea Nistor <mircea.nistor@mesh.xyz>" | ||
], | ||
"license": "ISC", | ||
"dependencies": { | ||
"did-jwt": "^5.4.0", | ||
"did-jwt": "^5.6.1", | ||
"did-resolver": "^3.1.0" | ||
@@ -36,22 +38,18 @@ }, | ||
"jest": { | ||
"transform": { | ||
"^.+\\.tsx?$": "ts-jest" | ||
}, | ||
"testRegex": "(/__tests__/.*|(\\.|/)(test|spec))\\.(jsx?|tsx?)$", | ||
"moduleFileExtensions": [ | ||
"ts", | ||
"tsx", | ||
"js", | ||
"jsx", | ||
"json" | ||
], | ||
"coverageDirectory": "./coverage/", | ||
"clearMocks": true, | ||
"collectCoverageFrom": [ | ||
"src/**/*.{ts,tsx}", | ||
"!src/**/*.d.ts", | ||
"!**/node_modules/**" | ||
"!**/node_modules/**", | ||
"!**/__tests__/**" | ||
], | ||
"testEnvironment": "node" | ||
"testEnvironment": "node", | ||
"testMatch": [ | ||
"**/__tests__/**/*.test.[jt]s" | ||
] | ||
}, | ||
"devDependencies": { | ||
"@babel/core": "7.14.6", | ||
"@babel/preset-env": "7.14.7", | ||
"@babel/preset-typescript": "7.14.5", | ||
"@semantic-release/changelog": "5.0.1", | ||
@@ -61,15 +59,21 @@ "@semantic-release/git": "9.0.0", | ||
"@types/jest": "26.0.23", | ||
"@types/node": "14.17.3", | ||
"@types/node": "15.12.4", | ||
"@typescript-eslint/eslint-plugin": "4.28.1", | ||
"@typescript-eslint/parser": "4.28.1", | ||
"codecov": "3.8.2", | ||
"eslint": "7.29.0", | ||
"eslint-config-prettier": "8.3.0", | ||
"eslint-plugin-jest": "24.3.6", | ||
"eslint-plugin-prettier": "3.4.0", | ||
"ethr-did": "2.1.4", | ||
"faker": "5.5.3", | ||
"jest": "27.0.4", | ||
"prettier": "2.3.1", | ||
"jest": "27.0.6", | ||
"microbundle": "0.13.3", | ||
"prettier": "2.3.2", | ||
"semantic-release": "17.4.4", | ||
"ts-jest": "27.0.3", | ||
"tslint": "6.1.3", | ||
"tslint-config-prettier": "1.18.0", | ||
"tslint-eslint-rules": "5.4.0", | ||
"typescript": "4.3.2" | ||
"typescript": "4.3.4" | ||
}, | ||
"engines": { | ||
"node": ">=14" | ||
} | ||
} |
@@ -0,5 +1,11 @@ | ||
[![npm](https://img.shields.io/npm/dt/did-jwt-vc.svg)](https://www.npmjs.com/package/did-jwt-vc) | ||
[![npm](https://img.shields.io/npm/v/did-jwt-vc.svg)](https://www.npmjs.com/package/did-jwt-vc) | ||
[![codecov](https://codecov.io/gh/decentralized-identity/did-jwt-vc/branch/master/graph/badge.svg)](https://codecov.io/gh/decentralized-identity/did-jwt-vc) | ||
# did-jwt-vc | ||
Create and verify W3C Verifiable Credentials and Presentations in JWT format | ||
## Installation | ||
``` | ||
@@ -22,3 +28,3 @@ npm install did-jwt-vc | ||
const issuer: Issuer = new EthrDID({ | ||
address: '0xf1232f840f3ad7d23fcdaa84d6c66dac24efb198', | ||
identifier: '0xf1232f840f3ad7d23fcdaa84d6c66dac24efb198', | ||
privateKey: 'd8b595680851765f38ea5405129244ba3cbad84467d190859f4c8b20c1ff6c75' | ||
@@ -95,3 +101,3 @@ }) | ||
const providerConfig = { | ||
rpcUrl: 'https://mainnet.infura.io/v3/<YOUR Infura.io PROJECT ID>', | ||
rpcUrl: 'https://mainnet.infura.io/v3/<YOUR infura.io PROJECT ID>', | ||
registry: '0xdca7ef03e98e0dc2b855be647c39abe984fcf21b' | ||
@@ -221,9 +227,9 @@ } | ||
The result of the verification methods, when successful, also conveniently contain the decoded and parsed payloads, in | ||
a format that closely matches the [W3C data model](https://www.w3.org/TR/vc-data-model/) for verifiable credentials and presentations. | ||
This makes it easier to work with both credential encodings in the same system. | ||
This parsed payload also shows a `proof` property that lists the full JWT credential or presentation. | ||
The result of the verification methods, when successful, also conveniently contain the decoded and parsed payloads, in a | ||
format that closely matches the [W3C data model](https://www.w3.org/TR/vc-data-model/) for verifiable credentials and | ||
presentations. This makes it easier to work with both credential encodings in the same system. This parsed payload also | ||
shows a `proof` property that lists the full JWT credential or presentation. | ||
The `JwtProof2020` is a synthetic proof type, usable for differentiating credentials by type. | ||
It is not a registered W3C VC Data Model algorithm and should not be treated as such. | ||
The `JwtProof2020` is a synthetic proof type, usable for differentiating credentials by type. It is not a registered W3C | ||
VC Data Model algorithm and should not be treated as such. | ||
@@ -230,0 +236,0 @@ Also note that the `@context` fields that appear in this parsed payload are the same as the ones in the incoming JWT. |
@@ -10,3 +10,3 @@ import { | ||
PresentationPayload, | ||
W3CPresentation | ||
W3CPresentation, | ||
} from './types' | ||
@@ -16,35 +16,19 @@ import { decodeJWT } from 'did-jwt' | ||
export function asArray(input: any) { | ||
return Array.isArray(input) ? input : [input] | ||
// eslint-disable-next-line @typescript-eslint/no-explicit-any | ||
export function asArray(arg: any | any[]): any[] { | ||
return Array.isArray(arg) ? arg : [arg] | ||
} | ||
function deepCopy<T>(obj: T): T { | ||
let copy | ||
// Handle the 3 simple types, and null or undefined | ||
if (null === obj || 'object' !== typeof obj) return obj | ||
// Handle Date | ||
if (obj instanceof Date) { | ||
copy = new Date() | ||
copy.setTime(obj.getTime()) | ||
return copy | ||
} | ||
// Handle Array | ||
if (obj instanceof Array) { | ||
copy = obj.map(deepCopy) | ||
return copy | ||
} | ||
// Handle Object | ||
if (obj instanceof Object) { | ||
copy = {} | ||
for (const key of Object.keys(obj)) { | ||
copy[key] = deepCopy(obj[key]) | ||
} | ||
return copy | ||
} | ||
throw new Error("Unable to copy obj! Its type isn't supported.") | ||
function deepCopy<T>(source: T): T { | ||
return Array.isArray(source) | ||
? source.map((item) => deepCopy(item)) | ||
: source instanceof Date | ||
? new Date(source.getTime()) | ||
: source && typeof source === 'object' | ||
? Object.getOwnPropertyNames(source).reduce((o, prop) => { | ||
Object.defineProperty(o, prop, Object.getOwnPropertyDescriptor(source, prop) as NonNullable<PropertyDescriptor>) | ||
o[prop] = deepCopy(source[prop as keyof T]) | ||
return o | ||
}, Object.create(Object.getPrototypeOf(source))) | ||
: (source as T) | ||
} | ||
@@ -61,12 +45,14 @@ | ||
const obj = { ...input } | ||
Object.keys(obj).forEach((key) => obj[key] === undefined && delete obj[key]) | ||
Object.keys(obj).forEach((key) => obj[key as keyof T] === undefined && delete obj[key as keyof T]) | ||
return obj | ||
} | ||
export function isLegacyAttestationFormat(payload: any): boolean { | ||
// eslint-disable-next-line @typescript-eslint/no-explicit-any | ||
export function isLegacyAttestationFormat(payload: Record<string, any>): boolean { | ||
// payload is an object and has all the required fields of old attestation format | ||
return payload instanceof Object && payload.sub && payload.iss && payload.claim && payload.iat | ||
return typeof payload === 'object' && payload.sub && payload.iss && payload.claim && payload.iat | ||
} | ||
export function attestationToVcFormat(payload: any): JwtCredentialPayload { | ||
// eslint-disable-next-line @typescript-eslint/no-explicit-any | ||
export function attestationToVcFormat(payload: Record<string, any>): JwtCredentialPayload { | ||
const { iat, nbf, claim, vc, ...rest } = payload | ||
@@ -79,4 +65,4 @@ const result: JwtCredentialPayload = { | ||
type: [DEFAULT_VC_TYPE], | ||
credentialSubject: payload.claim | ||
} | ||
credentialSubject: claim, | ||
}, | ||
} | ||
@@ -89,3 +75,3 @@ if (vc) payload.issVc = vc | ||
input: Partial<JwtCredentialPayload>, | ||
removeOriginalFields: boolean = true | ||
removeOriginalFields = true | ||
): W3CCredential { | ||
@@ -100,3 +86,3 @@ let result: Partial<CredentialPayload> = deepCopy(input) | ||
result.credentialSubject = { ...input.credentialSubject, ...input.vc?.credentialSubject } | ||
if (input.sub && !input.credentialSubject?.id) { | ||
if (input.sub && !input.credentialSubject?.id && result.credentialSubject) { | ||
result.credentialSubject.id = input.sub | ||
@@ -149,3 +135,3 @@ if (removeOriginalFields) { | ||
...asArray(input['@context']), | ||
...asArray(input.vc?.['@context']) | ||
...asArray(input.vc?.['@context']), | ||
].filter(notEmpty) | ||
@@ -187,3 +173,3 @@ result['@context'] = [...new Set(contextArray)] | ||
function normalizeJwtCredential(input: JWT, removeOriginalFields: boolean = true): Verifiable<W3CCredential> { | ||
function normalizeJwtCredential(input: JWT, removeOriginalFields = true): Verifiable<W3CCredential> { | ||
let decoded | ||
@@ -199,4 +185,4 @@ try { | ||
type: DEFAULT_JWT_PROOF_TYPE, | ||
jwt: input | ||
} | ||
jwt: input, | ||
}, | ||
} | ||
@@ -213,3 +199,3 @@ } | ||
input: Partial<VerifiableCredential> | Partial<JwtCredentialPayload>, | ||
removeOriginalFields: boolean = true | ||
removeOriginalFields = true | ||
): Verifiable<W3CCredential> { | ||
@@ -220,3 +206,3 @@ if (typeof input === 'string') { | ||
} else { | ||
let parsed: object | ||
let parsed: Record<string, unknown> | ||
try { | ||
@@ -242,3 +228,3 @@ parsed = JSON.parse(input) | ||
*/ | ||
type DeepPartial<T> = T extends object ? { [K in keyof T]?: DeepPartial<T[K]> } : T | ||
type DeepPartial<T> = T extends Record<string, unknown> ? { [K in keyof T]?: DeepPartial<T[K]> } : T | ||
@@ -253,7 +239,11 @@ /** | ||
input: Partial<CredentialPayload> | DeepPartial<JwtCredentialPayload>, | ||
removeOriginalFields: boolean = true | ||
removeOriginalFields = true | ||
): JwtCredentialPayload { | ||
if (Array.isArray(input.credentialSubject)) throw Error('credentialSubject of type array not supported') | ||
const result: Partial<JwtCredentialPayload> = deepCopy({ vc: { ...input.vc }, ...input }) | ||
const result: Partial<JwtCredentialPayload> = deepCopy({ | ||
vc: { ...input.vc }, | ||
...input, | ||
}) as Partial<JwtCredentialPayload> | ||
result.vc = result.vc as NonNullable<typeof result.vc> | ||
@@ -271,3 +261,3 @@ const credentialSubject = { ...input.credentialSubject, ...input.vc?.credentialSubject } | ||
...asArray(input['@context']), | ||
...asArray(input.vc?.['@context']) | ||
...asArray(input.vc?.['@context']), | ||
].filter(notEmpty) | ||
@@ -341,3 +331,3 @@ result.vc['@context'] = [...new Set(contextEntries)] | ||
for (let prop of additionalPropNames) { | ||
for (const prop of additionalPropNames) { | ||
if (input[prop]) { | ||
@@ -358,3 +348,3 @@ if (!result.vc[prop]) { | ||
input: DeepPartial<JwtPresentationPayload>, | ||
removeOriginalFields: boolean = true | ||
removeOriginalFields = true | ||
): W3CPresentation { | ||
@@ -365,3 +355,3 @@ const result: Partial<PresentationPayload> = deepCopy(input) | ||
...asArray(input.verifiableCredential), | ||
...asArray(input.vp?.verifiableCredential) | ||
...asArray(input.vp?.verifiableCredential), | ||
].filter(notEmpty) | ||
@@ -406,3 +396,3 @@ result.verifiableCredential = result.verifiableCredential.map((cred) => { | ||
...asArray(input['@context']), | ||
...asArray(input.vp?.['@context']) | ||
...asArray(input.vp?.['@context']), | ||
].filter(notEmpty) | ||
@@ -442,3 +432,3 @@ result['@context'] = [...new Set(contexts)] | ||
function normalizeJwtPresentation(input: JWT, removeOriginalFields: boolean = true): Verifiable<W3CPresentation> { | ||
function normalizeJwtPresentation(input: JWT, removeOriginalFields = true): Verifiable<W3CPresentation> { | ||
let decoded | ||
@@ -454,4 +444,4 @@ try { | ||
type: DEFAULT_JWT_PROOF_TYPE, | ||
jwt: input | ||
} | ||
jwt: input, | ||
}, | ||
} | ||
@@ -466,3 +456,3 @@ } | ||
input: Partial<PresentationPayload> | DeepPartial<JwtPresentationPayload> | JWT, | ||
removeOriginalFields: boolean = true | ||
removeOriginalFields = true | ||
): Verifiable<W3CPresentation> { | ||
@@ -473,3 +463,3 @@ if (typeof input === 'string') { | ||
} else { | ||
let parsed: object | ||
let parsed: Record<string, unknown> | ||
try { | ||
@@ -500,5 +490,9 @@ parsed = JSON.parse(input) | ||
input: Partial<PresentationPayload> | DeepPartial<JwtPresentationPayload>, | ||
removeOriginalFields: boolean = true | ||
removeOriginalFields = true | ||
): JwtPresentationPayload { | ||
const result: Partial<JwtPresentationPayload> = deepCopy({ vp: { ...input.vp }, ...input }) | ||
const result: Partial<JwtPresentationPayload> = deepCopy({ | ||
vp: { ...input.vp }, | ||
...input, | ||
}) as Partial<JwtPresentationPayload> | ||
result.vp = result.vp as NonNullable<typeof result.vp> | ||
@@ -508,3 +502,3 @@ const contextEntries = [ | ||
...asArray(input['@context']), | ||
...asArray(input.vp?.['@context']) | ||
...asArray(input.vp?.['@context']), | ||
].filter(notEmpty) | ||
@@ -550,14 +544,17 @@ result.vp['@context'] = [...new Set(contextEntries)] | ||
result.vp.verifiableCredential = [ | ||
...asArray(result.verifiableCredential), | ||
...asArray(result.vp?.verifiableCredential) | ||
] | ||
.filter(notEmpty) | ||
.map((credential: VerifiableCredential) => { | ||
if (typeof credential === 'object' && credential.proof?.jwt) { | ||
return credential.proof.jwt | ||
} else { | ||
return credential | ||
} | ||
}) | ||
if (result.verifiableCredential || result.vp?.verifiableCredential) { | ||
result.vp.verifiableCredential = [ | ||
...asArray(result.verifiableCredential), | ||
...asArray(result.vp?.verifiableCredential), | ||
] | ||
.filter(notEmpty) | ||
.map((credential: VerifiableCredential) => { | ||
if (typeof credential === 'object' && credential.proof?.jwt) { | ||
return credential.proof.jwt | ||
} else { | ||
return credential | ||
} | ||
}) | ||
} | ||
if (removeOriginalFields) { | ||
@@ -564,0 +561,0 @@ delete result.verifiableCredential |
@@ -22,3 +22,3 @@ import { createJWT, verifyJWT } from 'did-jwt' | ||
CreateCredentialOptions, | ||
VerifyCredentialOptions | ||
VerifyCredentialOptions, | ||
} from './types' | ||
@@ -31,3 +31,3 @@ import { | ||
asArray, | ||
notEmpty | ||
notEmpty, | ||
} from './converters' | ||
@@ -50,3 +50,3 @@ export { | ||
normalizeCredential, | ||
normalizePresentation | ||
normalizePresentation, | ||
} | ||
@@ -75,3 +75,3 @@ | ||
iat: undefined, | ||
...transformCredentialInput(payload, options.removeOriginalFields) | ||
...transformCredentialInput(payload, options.removeOriginalFields), | ||
} | ||
@@ -82,8 +82,8 @@ validateJwtCredentialPayload(parsedPayload) | ||
{ | ||
issuer: issuer.did || parsedPayload.iss, | ||
signer: issuer.signer | ||
issuer: issuer.did || parsedPayload.iss || '', | ||
signer: issuer.signer, | ||
}, | ||
{ | ||
...options.header, | ||
alg: issuer.alg || options.header?.alg || JWT_ALG | ||
alg: issuer.alg || options.header?.alg || JWT_ALG, | ||
} | ||
@@ -115,3 +115,3 @@ ) | ||
iat: undefined, | ||
...transformPresentationInput(payload, options?.removeOriginalFields) | ||
...transformPresentationInput(payload, options?.removeOriginalFields), | ||
} | ||
@@ -134,8 +134,8 @@ | ||
{ | ||
issuer: holder.did || parsedPayload.iss, | ||
signer: holder.signer | ||
issuer: holder.did || parsedPayload.iss || '', | ||
signer: holder.signer, | ||
}, | ||
{ | ||
...options.header, | ||
alg: holder.alg || options.header?.alg || JWT_ALG | ||
alg: holder.alg || options.header?.alg || JWT_ALG, | ||
} | ||
@@ -164,10 +164,10 @@ ) | ||
validators.validateVpType(payload.vp.type) | ||
if (payload.vp.verifiableCredential.length < 1) { | ||
throw new TypeError('vp.verifiableCredential must not be empty') | ||
} | ||
for (const vc of asArray(payload.vp.verifiableCredential)) { | ||
if (typeof vc === 'string') { | ||
validators.validateJwtFormat(vc) | ||
} else { | ||
validateCredentialPayload(vc) | ||
// empty credential array is allowed | ||
if (payload.vp.verifiableCredential && payload.vp.verifiableCredential.length >= 1) { | ||
for (const vc of asArray(payload.vp.verifiableCredential)) { | ||
if (typeof vc === 'string') { | ||
validators.validateJwtFormat(vc) | ||
} else { | ||
validateCredentialPayload(vc) | ||
} | ||
} | ||
@@ -181,10 +181,10 @@ } | ||
validators.validateVpType(payload.type) | ||
if (payload.verifiableCredential.length < 1) { | ||
throw new TypeError('vp.verifiableCredential must not be empty') | ||
} | ||
for (const vc of payload.verifiableCredential) { | ||
if (typeof vc === 'string') { | ||
validators.validateJwtFormat(vc) | ||
} else { | ||
validateCredentialPayload(vc) | ||
// empty credential array is allowed | ||
if (payload.verifiableCredential && payload.verifiableCredential.length >= 1) { | ||
for (const vc of payload.verifiableCredential) { | ||
if (typeof vc === 'string') { | ||
validators.validateJwtFormat(vc) | ||
} else { | ||
validateCredentialPayload(vc) | ||
} | ||
} | ||
@@ -209,3 +209,3 @@ } | ||
const verified: Partial<VerifiedCredential> = await verifyJWT(vc, { resolver, ...options }) | ||
verified.verifiableCredential = normalizeCredential(verified.jwt, options?.removeOriginalFields) | ||
verified.verifiableCredential = normalizeCredential(verified.jwt as string, options?.removeOriginalFields) | ||
validateCredentialPayload(verified.verifiableCredential) | ||
@@ -222,3 +222,6 @@ return verified as VerifiedCredential | ||
*/ | ||
export function verifyPresentationPayloadOptions(payload: JwtPresentationPayload, options: VerifyPresentationOptions) { | ||
export function verifyPresentationPayloadOptions( | ||
payload: JwtPresentationPayload, | ||
options: VerifyPresentationOptions | ||
): void { | ||
if (options.challenge && options.challenge !== payload.nonce) { | ||
@@ -257,6 +260,6 @@ throw new Error(`Presentation does not contain the mandatory challenge (JWT: nonce) for : ${options.challenge}`) | ||
const verified: Partial<VerifiedPresentation> = await verifyJWT(presentation, { resolver, ...options }) | ||
verifyPresentationPayloadOptions(verified.payload, options) | ||
verified.verifiablePresentation = normalizePresentation(verified.jwt, options?.removeOriginalFields) | ||
verifyPresentationPayloadOptions(verified.payload as JwtPresentationPayload, options) | ||
verified.verifiablePresentation = normalizePresentation(verified.jwt as string, options?.removeOriginalFields) | ||
validatePresentationPayload(verified.verifiablePresentation) | ||
return verified as VerifiedPresentation | ||
} |
import { Signer, JWTVerified, JWTHeader } from 'did-jwt' | ||
export interface JwtCredentialSubject { | ||
[x: string]: any | ||
} | ||
// eslint-disable-next-line @typescript-eslint/no-explicit-any | ||
export type JwtCredentialSubject = Record<string, any> | ||
@@ -19,3 +18,3 @@ export interface CredentialStatus { | ||
sub?: string | ||
vc: { | ||
vc: Extensible<{ | ||
'@context': string[] | string | ||
@@ -25,6 +24,7 @@ type: string[] | string | ||
credentialStatus?: CredentialStatus | ||
// eslint-disable-next-line @typescript-eslint/no-explicit-any | ||
evidence?: any | ||
// eslint-disable-next-line @typescript-eslint/no-explicit-any | ||
termsOfUse?: any | ||
[x: string]: any | ||
} | ||
}> | ||
nbf?: number | ||
@@ -34,2 +34,3 @@ aud?: string | string[] | ||
jti?: string | ||
// eslint-disable-next-line @typescript-eslint/no-explicit-any | ||
[x: string]: any | ||
@@ -43,8 +44,7 @@ } | ||
export interface JwtPresentationPayload { | ||
vp: { | ||
vp: Extensible<{ | ||
'@context': string[] | string | ||
type: string[] | string | ||
verifiableCredential: VerifiableCredential[] | VerifiableCredential | ||
[x: string]: any | ||
} | ||
verifiableCredential?: VerifiableCredential[] | VerifiableCredential | ||
}> | ||
iss?: string | ||
@@ -56,6 +56,7 @@ aud?: string | string[] | ||
nonce?: string | ||
// eslint-disable-next-line @typescript-eslint/no-explicit-any | ||
[x: string]: any | ||
} | ||
export type IssuerType = { id: string; [x: string]: any } | string | ||
export type IssuerType = Extensible<{ id: string }> | string | ||
export type DateType = string | Date | ||
@@ -72,8 +73,9 @@ /** | ||
expirationDate?: DateType | ||
credentialSubject: { | ||
credentialSubject: Extensible<{ | ||
id?: string | ||
[x: string]: any | ||
} | ||
}> | ||
credentialStatus?: CredentialStatus | ||
// eslint-disable-next-line @typescript-eslint/no-explicit-any | ||
evidence?: any | ||
// eslint-disable-next-line @typescript-eslint/no-explicit-any | ||
termsOfUse?: any | ||
@@ -103,2 +105,3 @@ } | ||
type Replace<T, U> = Omit<T, keyof U> & U | ||
// eslint-disable-next-line @typescript-eslint/no-explicit-any | ||
type Extensible<T> = T & { [x: string]: any } | ||
@@ -125,3 +128,3 @@ | ||
id?: string | ||
verifiableCredential: VerifiableCredential[] | ||
verifiableCredential?: VerifiableCredential[] | ||
holder: string | ||
@@ -143,3 +146,3 @@ verifier?: string | string[] | ||
verifier: string[] | ||
verifiableCredential: Verifiable<W3CCredential>[] | ||
verifiableCredential?: Verifiable<W3CCredential>[] | ||
} | ||
@@ -158,2 +161,3 @@ | ||
type?: string | ||
// eslint-disable-next-line @typescript-eslint/no-explicit-any | ||
[x: string]: any | ||
@@ -233,3 +237,3 @@ } | ||
header?: Partial<JWTHeader> | ||
// eslint-disable-next-line @typescript-eslint/no-explicit-any | ||
[x: string]: any | ||
@@ -242,5 +246,4 @@ } | ||
*/ | ||
export interface VerifyCredentialOptions { | ||
[x: string]: any | ||
} | ||
// eslint-disable-next-line @typescript-eslint/no-explicit-any | ||
export type VerifyCredentialOptions = Record<string, any> | ||
@@ -247,0 +250,0 @@ /** |
import { DEFAULT_CONTEXT, DEFAULT_VC_TYPE, DEFAULT_VP_TYPE, JWT_FORMAT } from './constants' | ||
import { JwtCredentialSubject, DateType } from './types' | ||
import { VerifiableCredential } from 'src' | ||
import { VerifiableCredential } from '.' | ||
import { asArray } from './converters' | ||
function isDateObject(input: any) { | ||
return input && Object.prototype.toString.call(input) === '[object Date]' && !isNaN(input) | ||
// eslint-disable-next-line @typescript-eslint/no-explicit-any | ||
function isDateObject(input: any): input is Date { | ||
return input && !isNaN(input) && Object.prototype.toString.call(input) === '[object Date]' | ||
} | ||
@@ -9,0 +10,0 @@ |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is too big to display
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
Minified code
QualityThis package contains minified code. This may be harmless in some cases where minified code is included in packaged libraries, however packages on npm should not minify code.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
404902
237
22
29
3338
3
Updateddid-jwt@^5.6.1