diff --git a/package.json b/package.json index 15ac7d3..ad0ca9a 100644 --- a/package.json +++ b/package.json @@ -30,12 +30,12 @@ "@typescript-eslint/eslint-plugin": "^2.17.0", "@typescript-eslint/parser": "^2.17.0", "eslint": "^6.8.0", - "fast-deep-equal": "^2.0.1", "nyc": "^15.0.0", "tape": "^4.9.2", "typescript": "^4.0.3" }, "dependencies": { + "fast-deep-equal": "^2.0.1", "@metamask/controllers": "^3.1.0", "eth-rpc-errors": "^3.0.0", "is-subset": "^0.1.1", diff --git a/src/caveats.ts b/src/caveats.ts index 8564dd7..92275c8 100644 --- a/src/caveats.ts +++ b/src/caveats.ts @@ -2,6 +2,7 @@ import { JsonRpcMiddleware } from 'json-rpc-engine'; import { IOcapLdCaveat } from './@types/ocap-ld'; import { unauthorized } from './errors'; import isSubset from 'is-subset'; +import equal from 'fast-deep-equal'; export type ICaveatFunction = JsonRpcMiddleware; @@ -25,7 +26,7 @@ export const requireParams: ICaveatFunctionGenerator = function requireParams (s }; /* - * Filters array results shallowly. + * Filters array results. */ export const filterResponse: ICaveatFunctionGenerator = function filterResponse (serialized: IOcapLdCaveat) { const { value } = serialized; @@ -34,7 +35,10 @@ export const filterResponse: ICaveatFunctionGenerator = function filterResponse next((done) => { if (Array.isArray(res.result)) { res.result = res.result.filter((item) => { - return value.includes(item); + const findResult = value.find((v: any) => { + return equal(v, item); + }); + return findResult !== undefined; }); } done(); diff --git a/test/caveats.js b/test/caveats.js index 17d2bf3..1661c97 100644 --- a/test/caveats.js +++ b/test/caveats.js @@ -186,6 +186,62 @@ test('filterResponse caveat returns empty if params are not a subset.', async (t t.end(); }); +test('filterResponse caveat passes through subset portion of response when objects are used', async (t) => { + const domain = { origin: 'www.metamask.io' }; + + const ctrl = new CapabilitiesController({ + restrictedMethods: { + 'write': { + method: (_req, res, _next, end) => { + res.result = [{ foo: 'bar' }, { baz: 'boo' }, 3, 4, 5]; + end(); + }, + }, + }, + + // User approves on condition of first arg being 'foo', + // and second arg having the 'bar': 'baz' value. + requestUserApproval: async (permissionsRequest) => { + const perms = permissionsRequest.permissions; + perms.write.caveats = [ + { type: 'filterResponse', value: [{ foo: 'bar' }, { baz: 'boo' }, 3] }, + ]; + return perms; + }, + }, + { + domains: {}, + }); + + try { + let req = { + method: 'requestPermissions', + params: [ + { + 'write': {}, + }, + ], + }; + + await sendRpcMethodWithResponse(ctrl, domain, req); + + // Now let's call that restricted method: + req = { + method: 'write', + params: [], + }; + + const result = await sendRpcMethodWithResponse(ctrl, domain, req); + + t.ok(result, 'should succeed'); + t.deepEqual(result, [{ foo: 'bar' }, { baz: 'boo' }, 3], 'returned the correct subset'); + + } catch (err) { + t.notOk(err, 'should not throw'); + } + t.end(); +}); + test('filterResponse caveat passes through subset portion of response', async (t) => { const domain = { origin: 'www.metamask.io' };