Skip to content

Commit

Permalink
feat: createVP rpc method accepts VCs instead of VC IDs (#247)
Browse files Browse the repository at this point in the history
* feat: change parameter to actual vcs

* fix: datastore combobox

* fix: linting problems

* fix: params tests

* fix: tests

* fix: linting errors

* fix: linting error

* chore: fix lint issues

---------

Co-authored-by: Martin Domajnko <domajnko.martin@gmail.com>
  • Loading branch information
andyv09 and martines3000 authored Jun 20, 2023
1 parent a516414 commit 006f27c
Show file tree
Hide file tree
Showing 12 changed files with 28 additions and 200 deletions.
27 changes: 5 additions & 22 deletions packages/dapp/src/components/CreatePresentationDisplay/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,14 +3,15 @@
import { useState } from 'react';
import Link from 'next/link';
import {
AvailableVCStores,
QueryVCsRequestResult,
SupportedProofFormats,
VCRequest,
} from '@blockchain-lab-um/masca-types';
import { isError } from '@blockchain-lab-um/utils';
import { ArrowLeftIcon } from '@heroicons/react/20/solid';
import { W3CVerifiablePresentation } from '@veramo/core';
import {
W3CVerifiableCredential,
W3CVerifiablePresentation,
} from '@veramo/core';
import { useTranslations } from 'next-intl';
import { shallow } from 'zustand/shallow';

Expand Down Expand Up @@ -59,25 +60,7 @@ const CreatePresentationDisplay = () => {
const handleCreateVP = async () => {
if (!api) return;
setLoading(true);
const vcs: VCRequest[] = selectedVCs.map((vc) => {
if (vc.metadata.store) {
if (typeof vc.metadata.store === 'string')
return {
id: vc.metadata.id,
metadata: {
store: vc.metadata.store as AvailableVCStores,
},
};
if (Array.isArray(vc.metadata.store))
return {
id: vc.metadata.id,
metadata: {
store: vc.metadata.store[0] as AvailableVCStores,
},
};
}
return { id: vc.metadata.id };
});
const vcs: W3CVerifiableCredential[] = selectedVCs.map((vc) => vc.data);

const proofOptions = { type: '', domain, challenge };

Expand Down
5 changes: 4 additions & 1 deletion packages/dapp/src/components/MetaMaskProvider/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -93,7 +93,10 @@ const MetaMaskProvider = ({ children }: MetaMaskProviderProps) => {
};

const enableMascaHandler = async () => {
const enableResult = await enableMasca(address, { snapId, version: 'latest' });
const enableResult = await enableMasca(address, {
snapId,
version: 'latest',
});
if (isError(enableResult)) {
// FIXME: This error is shown as [Object object]
throw new Error(enableResult.error);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -73,9 +73,9 @@ const DataStoreCombobox = ({ vcs, isConnected }: DataStoreComboboxProps) => {
>
{({ open }) => (
<div className="relative">
<div className="md:w-34 relative h-[37px] w-24 cursor-default overflow-hidden rounded-full shadow-md sm:text-sm md:h-[43px]">
<div className="md:w-34 relative flex h-[37px] w-28 cursor-default overflow-hidden rounded-full shadow-md sm:text-sm md:h-[43px]">
<Combobox.Input
className={`md:text-md dark:bg-navy-blue-700 dark:text-navy-blue-50 py-2.5 pl-5 text-sm text-gray-700 focus:outline-none md:py-3 ${
className={`md:text-md dark:bg-navy-blue-700 dark:text-navy-blue-50 w-full truncate py-2.5 pl-5 text-sm text-gray-700 focus:outline-none md:py-3 ${
!isConnected || vcs.length === 0
? 'bg-gray-50 text-gray-300'
: ' '
Expand All @@ -88,7 +88,7 @@ const DataStoreCombobox = ({ vcs, isConnected }: DataStoreComboboxProps) => {
placeholder="None"
onChange={(event) => setQuery(event.target.value)}
/>
<Combobox.Button className="absolute inset-y-0 right-0 flex items-center pr-2">
<Combobox.Button className="dark:bg-navy-blue-700 bg-white">
<>
<ChevronDownIcon
className={`animated-transition dark:text-navy-blue-50 h-3 w-3 text-gray-700 md:h-4 md:w-4 lg:h-5 lg:w-5 ${
Expand Down
11 changes: 2 additions & 9 deletions packages/docs/docs/tutorial/implementation.md
Original file line number Diff line number Diff line change
Expand Up @@ -133,24 +133,17 @@ const vcs = await api.queryVCs();

```typescript
export type CreateVPRequestParams = {
vcs: VCRequest[];
vcs: W3CVerifiableCredential[];
proofFormat?: 'jwt' | 'lds' | 'EthereumEip712Signature2021';
proofOptions?: {
type?: string;
domain?: string;
challenge?: string;
};
};

export type VCRequest = {
id: string;
metadata?: {
store?: AvailableVCStores;
};
};
```

`vcs` is a list of VCs to be included in a VP. Its an array of objects that need to contain `id` of a VC (Which can be obtained using the `queryVCs` method). `metadata` property is optional and it contains `store` property which defines where to look for VC with id `id`.
`vcs` is a list of VCs of type `W3CVerifiableCredential`.

`proofFormat` can be jwt, jsonld or EthereumEip712Signature2021.

Expand Down
4 changes: 2 additions & 2 deletions packages/docs/docs/tutorial/rpc-methods.md
Original file line number Diff line number Diff line change
Expand Up @@ -200,7 +200,7 @@ Returns a VC.

```typescript
export type CreateVPRequestParams = {
vcs: VCRequest[];
vcs: W3CVerifiableCredential[];
proofFormat?: 'jwt' | 'lds' | 'EthereumEip712Signature2021';
proofOptions?: {
type?: string;
Expand All @@ -217,7 +217,7 @@ export type VCRequest = {
};
```

`vcs` is a list of VCs to be included in a VP. Its an array of objects that need to contain `id` of a VC (Which can be obtained using the `queryVCs` method). `metadata` property is optional and it contains `store` property which defines where to look for VC with id `id`.
`vcs` is a list of VCs of type `W3CVerifiableCredential`.

`proofFormat` can be jwt, jsonld or EthereumEip712Signature2021.

Expand Down
2 changes: 1 addition & 1 deletion packages/snap/snap.manifest.json
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
"url": "https://github.com/blockchain-lab-um/masca.git"
},
"source": {
"shasum": "IHbjbsXPcJosGui7xtyIMcw1vpA5/NJ3CFgK5cqZ6ZI=",
"shasum": "42G0Z9Z2T7iGtxikhZdK0dG/4qojIVCqqg33n55XNJo=",
"location": {
"npm": {
"filePath": "dist/snap.js",
Expand Down
33 changes: 0 additions & 33 deletions packages/snap/src/utils/params.ts
Original file line number Diff line number Diff line change
Expand Up @@ -125,39 +125,6 @@ export function isValidCreateVPRequest(
) {
throw new Error('Type is not a string');
}

// Check if vcs is valid
param.vcs.forEach((vc) => {
if (
vc !== null &&
typeof vc === 'object' &&
'id' in vc &&
typeof vc.id === 'string'
) {
if (
'metadata' in vc &&
vc.metadata !== null &&
typeof vc.metadata === 'object' &&
'store' in vc.metadata &&
vc.metadata.store !== null &&
typeof vc.metadata.store === 'string' &&
!isAvailableVCStores(vc.metadata.store)
) {
throw new Error(`Store ${vc.metadata.store} is not supported!`);
}
if (
'metadata' in vc &&
vc.metadata !== null &&
typeof vc.metadata === 'object' &&
'store' in vc.metadata &&
vc.metadata.store !== null &&
typeof vc.metadata.store === 'string' &&
!isEnabledVCStore(account, state, vc.metadata?.store)
) {
throw new Error(`Store ${vc.metadata.store} is not enabled!`);
}
} else throw new Error('VC is invalid format');
});
return;
}

Expand Down
19 changes: 1 addition & 18 deletions packages/snap/src/utils/veramoUtils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -192,7 +192,7 @@ export async function veramoCreateVP(
},
createVPParams: CreateVPRequestParams
): Promise<VerifiablePresentation> {
const vcsMetadata = createVPParams.vcs;
const { vcs } = createVPParams;
const domain = createVPParams.proofOptions?.domain;
const challenge = createVPParams.proofOptions?.challenge;
const proofFormat = createVPParams.proofFormat
Expand All @@ -214,23 +214,6 @@ export async function veramoCreateVP(
agent
);

const vcs: W3CVerifiableCredential[] = [];

for (const vcMetadata of vcsMetadata) {
// eslint-disable-next-line no-await-in-loop
const vcObj = (await agent.query({
filter: {
type: 'id',
filter: vcMetadata.id,
},
options: { store: vcMetadata.metadata?.store },
})) as QueryVCsRequestResult[];
if (vcObj.length > 0) {
const vc: W3CVerifiableCredential = vcObj[0].data;
vcs.push(vc);
}
}

if (vcs.length === 0) {
throw new Error('VC does not exist');
}
Expand Down
48 changes: 4 additions & 44 deletions packages/snap/tests/rpc/onRpcRequest.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ import {
exampleDIDKey,
exampleTestKey,
exampleTestVCPayload,
exampleVC,
getDefaultSnapState,
jsonPath,
} from '../testUtils/constants';
Expand Down Expand Up @@ -947,7 +948,7 @@ describe('onRpcRequest', () => {
jsonrpc: '2.0',
method: 'createVP',
params: {
vcs: [{ id: saveRes.data[0].id, metadata: { store: 'snap' } }],
vcs: [exampleVC],
},
},
})) as Result<VerifiablePresentation>;
Expand Down Expand Up @@ -1005,7 +1006,7 @@ describe('onRpcRequest', () => {
jsonrpc: '2.0',
method: 'createVP',
params: {
vcs: [{ id: saveRes.data[0].id }],
vcs: [exampleVC],
},
},
})) as Result<VerifiablePresentation>;
Expand All @@ -1026,47 +1027,6 @@ describe('onRpcRequest', () => {

expect.assertions(1);
});

it('should fail creating VP - VC does not exist', async () => {
snapMock.rpcMocks.snap_dialog.mockReturnValue(false);

let res = (await onRpcRequest({
origin: 'localhost',
request: {
id: 'test-id',
jsonrpc: '2.0',
method: 'saveVC',
params: {
verifiableCredential: exampleVeramoVCJWT,
options: { store: 'snap' },
},
},
})) as Result<unknown>;

if (isSuccess(res)) {
throw new Error('Should return error');
}

res = (await onRpcRequest({
origin: 'localhost',
request: {
id: 'test-id',
jsonrpc: '2.0',
method: 'createVP',
params: {
vcs: [{ id: 'test-id' }],
},
},
})) as Result<unknown>;

if (isSuccess(res)) {
throw new Error('Should return error');
}

expect(res.error).toBe('Error: VC does not exist');

expect.assertions(1);
});
});

describe('togglePopups', () => {
Expand Down Expand Up @@ -1677,7 +1637,7 @@ describe('onRpcRequest', () => {
jsonrpc: '2.0',
method: 'createVP',
params: {
vcs: [{ id: saveRes.data[0].id, metadata: { store: 'snap' } }],
vcs: [exampleVC],
},
},
})) as Result<VerifiablePresentation>;
Expand Down
35 changes: 0 additions & 35 deletions packages/snap/tests/utils/params.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -186,17 +186,6 @@ describe('Utils [params]', () => {
isValidCreateVPRequest
*/
describe('isValidCreateVPRequest', () => {
it('should fail for not enabled store', () => {
const state = getDefaultSnapState();
state.accountState[address].accountConfig.ssi.vcStore.ceramic = false;
expect(() =>
isValidCreateVPRequest(
{ vcs: [{ id: '123', metadata: { store: 'ceramic' } }] },
address,
state
)
).toThrow('Store ceramic is not enabled!');
});
it('should succeed if vcId is a string', () => {
expect(() =>
isValidCreateVPRequest(
Expand Down Expand Up @@ -256,18 +245,6 @@ describe('Utils [params]', () => {
)
).toThrow(Error);
});

it('should fail if vcId is a number', () => {
expect(() =>
isValidCreateVPRequest(
{
vcs: [{ id: 123 }],
},
address,
getDefaultSnapState()
)
).toThrow('VC is invalid format');
});
it('should fail if vcs is null', () => {
expect(() =>
isValidCreateVPRequest(
Expand Down Expand Up @@ -315,18 +292,6 @@ describe('Utils [params]', () => {
)
).not.toThrow('err');
});
it('should throw request with wrong store', () => {
expect(() =>
isValidCreateVPRequest(
{
vcs: [{ id: 'test-id', metadata: { store: 'snapp' } }],
proofFormat: 'jwt',
},
address,
getDefaultSnapState()
)
).toThrow('Store snapp is not supported!');
});

it('should not throw request with proofFormat and proofOptions', () => {
expect(() =>
Expand Down
Loading

0 comments on commit 006f27c

Please sign in to comment.