Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[fix]: update configuration for exporting package #25

Open
wants to merge 3 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
517 changes: 280 additions & 237 deletions package-lock.json

Large diffs are not rendered by default.

31 changes: 13 additions & 18 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -4,34 +4,25 @@
"description": "SSI SDK for Onyx W3C Verifiable Credentials",
"license": "Apache-2.0",
"source": "src/index.ts",
"types": "./lib/cjs/types/index.d.ts",
"main": "./lib/cjs/index.js",
"module": "./lib/esm/index.mjs",
"esnext": "./lib/esm/index.mjs",
"types": "./lib/esm/types/index.d.ts",
"type": "commonjs",
"files": [
"dist",
"lib",
"src",
"LICENSE"
],
"exports": {
".": {
"import": {
"types": "./lib/esm/types/index.d.ts",
"default": "./lib/esm/index.mjs"
},
"require": {
"types": "./lib/cjs/types/index.d.ts",
"default": "./lib/cjs/index.js"
}
}
},
"repository": {
"type": "git",
"url": "https://github.com/jpmorganchase/onyx-ssi-sdk"
},
"scripts": {
"clean": "rm -rf ./lib",
"build": "npm run clean && npm run build:esm && npm run build:cjs",
"build:esm": "tsc -p ./configs/tsconfig.esm.json && mv lib/esm/index.js lib/esm/index.mjs",
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The renaming is unnecessary.

"build:esm": "tsc -p ./configs/tsconfig.esm.json",
"build:cjs": "tsc -p ./configs/tsconfig.cjs.json",
"prepack": "npm run build",
"lint": "eslint .",
Expand All @@ -40,6 +31,7 @@
"keywords": [],
"author": "",
"devDependencies": {
"@nomicfoundation/hardhat-toolbox": "^2.0.2",
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Moved this to devDeps as it wasn't browser friendly but isn't used in production code.

"@types/jest": "^29.5.1",
"@types/jsonwebtoken": "^9.0.2",
"@types/mocha": "^10.0.1",
Expand All @@ -56,7 +48,6 @@
"@ethersproject/providers": "^5.6.8",
"@nomicfoundation/hardhat-chai-matchers": "^1.0.3",
"@nomicfoundation/hardhat-network-helpers": "^1.0.4",
"@nomicfoundation/hardhat-toolbox": "^2.0.2",
"@nomiclabs/hardhat-ethers": "^2.1.1",
"@nomiclabs/hardhat-etherscan": "^3.1.0",
"@nomiclabs/hardhat-solhint": "^2.0.1",
Expand All @@ -65,6 +56,8 @@
"@typechain/hardhat": "^6.1.2",
"@types/chai": "^4.3.5",
"@types/lodash": "^4.14.194",
"ajv": "^8.12.0",
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Replaced incompatible jsonschema with https://github.com/ajv-validator/ajv

"ajv-formats": "^3.0.1",
"axios": "^1.3.5",
"chai": "^4.3.7",
"did-jwt": "6.11.6",
Expand All @@ -74,9 +67,8 @@
"ethr-did-resolver": "^8.0.0",
"hardhat": "^2.14.0",
"hardhat-gas-reporter": "^1.0.9",
"jsonschema": "^1.4.1",
"jsonwebtoken": "^9.0.0",
"key-did-resolver": "1.4.0",
"jose": "^5.2.4",
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The jsonwebtoken library is targeting node enviroments. I replaced it with https://github.com/panva/jose

"key-did-resolver": "^1.4.0",
"lodash": "^4.17.21",
"loglevel": "^1.8.1",
"solidity-coverage": "^0.8.2",
Expand All @@ -86,5 +78,8 @@
"overrides": {
"flat": ">=5.0.1",
"minimatch": ">=3.0.5"
},
"browser": {
"fs": false
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This prevents bundler for containing incompatible fs lib to browser enviroments.

}
}
4 changes: 2 additions & 2 deletions src/services/common/did/did-key.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { DIDResolutionResult, DIDResolver, Resolver } from "did-resolver";
import {randomBytes} from "crypto"
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

crypto is not browser-compatible.

import { utils } from 'ethers';
import { DID, DIDMethod, DIDWithKeys } from "./did";
import { KeyUtils, KEY_ALG } from "../../../utils";
import { getResolver } from "key-did-resolver";
Expand All @@ -15,7 +15,7 @@ export class KeyDIDMethod implements DIDMethod {
*/
async create(): Promise<DIDWithKeys> {
const seed = () => {
return randomBytes(32)
return utils.randomBytes(32)
}

const key = await Ed25519KeyPair.generate({
Expand Down
27 changes: 16 additions & 11 deletions src/services/common/schemas/schemas.ts
Original file line number Diff line number Diff line change
@@ -1,15 +1,16 @@

import { validate } from 'jsonschema'
import Ajv from 'ajv'
import addFormats from "ajv-formats"
import { SchemaValidationFailureError } from '../../../errors'
import { HelperUtils } from '../../../utils/HelperUtils'
// import jsonSchemaDraft07 from 'ajv/dist/refs/json-schema-draft-07.json'

export class SchemaManager {

/**
* Reads in a [JSON schema](https://json-schema.org/specification-links.html#draft-7)
* for a Verifiable Credential from a remote location
*
* Once retrieved from the remote location, the schema will be validated using `jsonschema`
* Once retrieved from the remote location, the schema will be validated using `ajv`
*
* @param schemaLocation - the remote location of the schema file
* @returns a `Promise` that resolves to a Verifiable Credential {@link JsonSchema} object.
Expand All @@ -29,7 +30,7 @@ export class SchemaManager {
* Reads in a [JSON schema](https://json-schema.org/specification-links.html#draft-7)
* for a Verifiable Credential from a local file location
*
* Once retrieved from the location, the schema will be validated using jsonschema
* Once retrieved from the location, the schema will be validated using 'ajv'
*
* @param schemaLocation - the file path of the schema file
* @returns a `Promise` that resolves to a Verifiable Credential {@link JsonSchema} object.
Expand Down Expand Up @@ -66,9 +67,9 @@ export class SchemaManager {
}
const spec = await HelperUtils.axiosHelper(schemaUrl)
if(typeof spec === 'object') {
return spec
return spec.data ? spec.data : spec
}
return HelperUtils.parseJSON(spec)
return HelperUtils.parseJSON(spec)
}

/**
Expand All @@ -82,7 +83,10 @@ export class SchemaManager {
*/
static async validateSchema(schema: JsonSchema): Promise<boolean> {
const schemaSpec = await this.getSchemaSpec(schema)
return validate(schema, schemaSpec, {throwError: true}).valid
const ajv = new Ajv({ meta: false })
addFormats(ajv)
const validate = ajv.compile(schemaSpec)
return validate(schema)
}

/**
Expand All @@ -91,19 +95,20 @@ export class SchemaManager {
* [`credentialSchema`](https://www.w3.org/TR/vc-data-model/#data-schemas) defined
* in the Verifiable Credential
*
* `validate` from jsonschema is used to do the schema validation
* `validate` from ajv is used to do the schema validation
*
* Verifying the `credentialSubject` structure is a check the Verifier can perform
* to validate a Verifiable Credential
*
*
* @param credentialSubject the data object to be validated
* @param schema the `JsonSchema` that the `credentialSubject` should conform to
* @returns a `Promise` that resolves to if the validation succeeded.
* Throws jsonschema ValidationError if something goes wrong
* @returns `boolean` that indicates if the validation succeeded.
*/
static validateCredentialSubject(credentialSubject: object, schema: JsonSchema): boolean {
return validate(credentialSubject, schema, {throwError: true}).valid
const ajv = new Ajv()
const validate = ajv.compile(schema)
return validate(credentialSubject)
}
}

Expand Down
7 changes: 5 additions & 2 deletions src/services/common/signatures/jwt.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import { CredentialPayload, PresentationPayload, createVerifiableCredentialJwt,
import { ES256KSigner, hexToBytes, EdDSASigner } from 'did-jwt'
import { KEY_ALG } from "../../../utils";
import { isString } from 'lodash'
import {decode} from 'jsonwebtoken';
import { decodeJwt, decodeProtectedHeader } from 'jose';

export class JWTService implements SignatureService {
name = 'JWT'
Expand Down Expand Up @@ -97,7 +97,10 @@ export class JWTService implements SignatureService {
* @return decoded JWT object {header, payload, signature}
*/
decodeJWT(token: JWT) {
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Here we could add a simpler decodePayload function perhaps

return decode(token, {complete:true})
const header = decodeProtectedHeader(token)
const payload = decodeJwt(token);
const signature = token.split('.')[2]
return { header, payload, signature }
}
}

Expand Down
6 changes: 3 additions & 3 deletions src/services/issuer/credential.ts
Original file line number Diff line number Diff line change
Expand Up @@ -154,8 +154,8 @@ export async function revokeCredential(vcDID: DIDWithKeys, didMethod: DIDMethod)
export function getIssuerFromVC(vc: VerifiableCredential): DID | undefined {
const jwtService = new JWTService()
if(typeof vc === 'string') {
const credential = jwtService.decodeJWT(vc)?.payload as JWTPayload
return credential.iss
const { payload } = jwtService.decodeJWT(vc)
return payload.iss
} else {
return vc.issuer.id
}
Expand All @@ -170,7 +170,7 @@ export function getIssuerFromVC(vc: VerifiableCredential): DID | undefined {
export function getSubjectFromVP(vc: VerifiableCredential): DID | undefined {
const jwtService = new JWTService()
if(typeof vc === 'string') {
const credential = jwtService.decodeJWT(vc)?.payload as JWTPayload
const credential = jwtService.decodeJWT(vc) as JWTPayload
return credential.sub as string
} else {
return vc.credentialSubject.id
Expand Down
4 changes: 4 additions & 0 deletions src/utils/HelperUtils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,10 @@ export class HelperUtils {
* Throws `ReadFileJsonFailureError` if reading or parsing fails
*/
static async fileReaderJSON(location: string) {
if (typeof window !== 'undefined') {
// Check if we are in a browser env
throw Error(`Operation 'fileReaderJSON' not supported in browser enviroment`)
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Throwing error, if caller wants to use this function, in web enviroment.

}
try {
const fileText = fs.readFileSync(location, 'utf-8');
return HelperUtils.parseJSON(fileText)
Expand Down
17 changes: 7 additions & 10 deletions tests/unit/schemas/schemas.test.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
import { ValidationError } from "jsonschema";
import { AxiosRequestFailureError, JsonParseError, ReadFileJsonFailureError, SchemaValidationFailureError } from "../../../src/errors";
import { SchemaManager } from "../../../src/services/common";
import { HelperUtils } from "../../../src/utils";
Expand Down Expand Up @@ -110,10 +109,8 @@ describe('schema utilities', () => {
})

it('Rejects a credential subject with additional properties', async () => {

expect(() => SchemaManager.validateCredentialSubject(
{...nameCredentialSubject, id: "did:key:123"}, nameSchema))
.toThrowError(ValidationError)
const result = await SchemaManager.validateCredentialSubject({...nameCredentialSubject, id: "did:key:123"}, nameSchema)
expect(result).toEqual(false);
})

//can we test mixing schema draft specs??
Expand Down Expand Up @@ -175,15 +172,15 @@ describe('schema utilities', () => {
minProperties: { '$ref': '#/definitions/nonNegativeIntegerDefault0' },
required: { '$ref': '#/definitions/stringArray' },
additionalProperties: { '$ref': '#' },
definitions: { type: 'object', additionalProperties: [Object], default: {} },
properties: { type: 'object', additionalProperties: [Object], default: {} },
definitions: { type: 'object', additionalProperties: { '$ref': '#' }, default: {} },
properties: { type: 'object', additionalProperties: { '$ref': '#' }, default: {} },
patternProperties: {
type: 'object',
additionalProperties: [Object],
propertyNames: [Object],
additionalProperties: { '$ref': '#' },
propertyNames: { '$ref': '#' },
default: {}
},
dependencies: { type: 'object', additionalProperties: [Object] },
dependencies: { type: 'object', additionalProperties: { '$ref': '#' } },
propertyNames: { '$ref': '#' },
const: true,
enum: { type: 'array', items: true, minItems: 1, uniqueItems: true },
Expand Down