Skip to content

Commit bdc833f

Browse files
authored
Add component validation to SnapInterfaceController (#2144)
1 parent 12b4b2e commit bdc833f

File tree

7 files changed

+249
-280
lines changed

7 files changed

+249
-280
lines changed

packages/snaps-controllers/src/interface/SnapInterfaceController.test.ts

+151-25
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import type { SnapId } from '@metamask/snaps-sdk';
2-
import { form, input } from '@metamask/snaps-sdk';
2+
import { form, input, panel, text } from '@metamask/snaps-sdk';
33
import { MOCK_SNAP_ID } from '@metamask/snaps-utils/test-utils';
44

55
import {
@@ -10,7 +10,7 @@ import { SnapInterfaceController } from './SnapInterfaceController';
1010

1111
describe('SnapInterfaceController', () => {
1212
describe('createInterface', () => {
13-
it('can create a new interface', () => {
13+
it('can create a new interface', async () => {
1414
const rootMessenger = getRootSnapInterfaceControllerMessenger();
1515
const controllerMessenger =
1616
getRestrictedSnapInterfaceControllerMessenger(rootMessenger);
@@ -20,12 +20,15 @@ describe('SnapInterfaceController', () => {
2020
messenger: controllerMessenger,
2121
});
2222

23-
const components = form({
24-
name: 'foo',
25-
children: [input({ name: 'bar' })],
26-
});
23+
const components = panel([
24+
text('[foo](https://foo.bar)'),
25+
form({
26+
name: 'foo',
27+
children: [input({ name: 'bar' })],
28+
}),
29+
]);
2730

28-
const id = rootMessenger.call(
31+
const id = await rootMessenger.call(
2932
'SnapInterfaceController:createInterface',
3033
MOCK_SNAP_ID,
3134
components,
@@ -37,13 +40,74 @@ describe('SnapInterfaceController', () => {
3740
id,
3841
);
3942

43+
expect(rootMessenger.call).toHaveBeenNthCalledWith(
44+
2,
45+
'PhishingController:maybeUpdateState',
46+
);
47+
48+
expect(rootMessenger.call).toHaveBeenNthCalledWith(
49+
3,
50+
'PhishingController:testOrigin',
51+
'foo.bar',
52+
);
53+
4054
expect(content).toStrictEqual(components);
4155
expect(state).toStrictEqual({ foo: { bar: null } });
4256
});
57+
58+
it('throws if a link is on the phishing list', async () => {
59+
const rootMessenger = getRootSnapInterfaceControllerMessenger();
60+
const controllerMessenger = getRestrictedSnapInterfaceControllerMessenger(
61+
rootMessenger,
62+
false,
63+
);
64+
65+
rootMessenger.registerActionHandler(
66+
'PhishingController:maybeUpdateState',
67+
jest.fn(),
68+
);
69+
70+
rootMessenger.registerActionHandler(
71+
'PhishingController:testOrigin',
72+
() => ({ result: true, type: 'all' }),
73+
);
74+
75+
/* eslint-disable-next-line no-new */
76+
new SnapInterfaceController({
77+
messenger: controllerMessenger,
78+
});
79+
80+
const components = panel([
81+
text('[foo](https://foo.bar)'),
82+
form({
83+
name: 'foo',
84+
children: [input({ name: 'bar' })],
85+
}),
86+
]);
87+
88+
await expect(
89+
rootMessenger.call(
90+
'SnapInterfaceController:createInterface',
91+
MOCK_SNAP_ID,
92+
components,
93+
),
94+
).rejects.toThrow('Invalid URL: The specified URL is not allowed.');
95+
96+
expect(rootMessenger.call).toHaveBeenNthCalledWith(
97+
2,
98+
'PhishingController:maybeUpdateState',
99+
);
100+
101+
expect(rootMessenger.call).toHaveBeenNthCalledWith(
102+
3,
103+
'PhishingController:testOrigin',
104+
'foo.bar',
105+
);
106+
});
43107
});
44108

45109
describe('getInterface', () => {
46-
it('gets the interface', () => {
110+
it('gets the interface', async () => {
47111
const rootMessenger = getRootSnapInterfaceControllerMessenger();
48112
const controllerMessenger =
49113
getRestrictedSnapInterfaceControllerMessenger(rootMessenger);
@@ -58,7 +122,7 @@ describe('SnapInterfaceController', () => {
58122
children: [input({ name: 'bar' })],
59123
});
60124

61-
const id = rootMessenger.call(
125+
const id = await rootMessenger.call(
62126
'SnapInterfaceController:createInterface',
63127
MOCK_SNAP_ID,
64128
components,
@@ -72,7 +136,7 @@ describe('SnapInterfaceController', () => {
72136
expect(content).toStrictEqual(components);
73137
});
74138

75-
it('throws if the snap requesting the interface is not the one that created it', () => {
139+
it('throws if the snap requesting the interface is not the one that created it', async () => {
76140
const rootMessenger = getRootSnapInterfaceControllerMessenger();
77141
const controllerMessenger =
78142
getRestrictedSnapInterfaceControllerMessenger(rootMessenger);
@@ -87,7 +151,7 @@ describe('SnapInterfaceController', () => {
87151
children: [input({ name: 'bar' })],
88152
});
89153

90-
const id = rootMessenger.call(
154+
const id = await rootMessenger.call(
91155
'SnapInterfaceController:createInterface',
92156
MOCK_SNAP_ID,
93157
components,
@@ -123,7 +187,7 @@ describe('SnapInterfaceController', () => {
123187
});
124188

125189
describe('updateInterface', () => {
126-
it('can update an interface', () => {
190+
it('can update an interface', async () => {
127191
const rootMessenger = getRootSnapInterfaceControllerMessenger();
128192
const controllerMessenger =
129193
getRestrictedSnapInterfaceControllerMessenger(rootMessenger);
@@ -143,13 +207,13 @@ describe('SnapInterfaceController', () => {
143207
children: [input({ name: 'baz' })],
144208
});
145209

146-
const id = rootMessenger.call(
210+
const id = await rootMessenger.call(
147211
'SnapInterfaceController:createInterface',
148212
MOCK_SNAP_ID,
149213
components,
150214
);
151215

152-
rootMessenger.call(
216+
await rootMessenger.call(
153217
'SnapInterfaceController:updateInterface',
154218
MOCK_SNAP_ID,
155219
id,
@@ -166,7 +230,69 @@ describe('SnapInterfaceController', () => {
166230
expect(state).toStrictEqual({ foo: { baz: null } });
167231
});
168232

169-
it('throws if the interface does not exist', () => {
233+
it('throws if a link is on the phishing list', async () => {
234+
const rootMessenger = getRootSnapInterfaceControllerMessenger();
235+
const controllerMessenger = getRestrictedSnapInterfaceControllerMessenger(
236+
rootMessenger,
237+
false,
238+
);
239+
240+
rootMessenger.registerActionHandler(
241+
'PhishingController:maybeUpdateState',
242+
jest.fn(),
243+
);
244+
245+
rootMessenger.registerActionHandler(
246+
'PhishingController:testOrigin',
247+
() => ({ result: true, type: 'all' }),
248+
);
249+
250+
/* eslint-disable-next-line no-new */
251+
new SnapInterfaceController({
252+
messenger: controllerMessenger,
253+
});
254+
255+
const components = form({
256+
name: 'foo',
257+
children: [input({ name: 'bar' })],
258+
});
259+
260+
const newContent = panel([
261+
text('[foo](https://foo.bar)'),
262+
form({
263+
name: 'foo',
264+
children: [input({ name: 'baz' })],
265+
}),
266+
]);
267+
268+
const id = await rootMessenger.call(
269+
'SnapInterfaceController:createInterface',
270+
MOCK_SNAP_ID,
271+
components,
272+
);
273+
274+
await expect(
275+
rootMessenger.call(
276+
'SnapInterfaceController:updateInterface',
277+
MOCK_SNAP_ID,
278+
id,
279+
newContent,
280+
),
281+
).rejects.toThrow('Invalid URL: The specified URL is not allowed.');
282+
283+
expect(rootMessenger.call).toHaveBeenNthCalledWith(
284+
4,
285+
'PhishingController:maybeUpdateState',
286+
);
287+
288+
expect(rootMessenger.call).toHaveBeenNthCalledWith(
289+
5,
290+
'PhishingController:testOrigin',
291+
'foo.bar',
292+
);
293+
});
294+
295+
it('throws if the interface does not exist', async () => {
170296
const rootMessenger = getRootSnapInterfaceControllerMessenger();
171297
const controllerMessenger =
172298
getRestrictedSnapInterfaceControllerMessenger(rootMessenger);
@@ -178,17 +304,17 @@ describe('SnapInterfaceController', () => {
178304

179305
const content = form({ name: 'foo', children: [input({ name: 'bar' })] });
180306

181-
expect(() =>
307+
await expect(
182308
rootMessenger.call(
183309
'SnapInterfaceController:updateInterface',
184310
MOCK_SNAP_ID,
185311
'foo',
186312
content,
187313
),
188-
).toThrow("Interface with id 'foo' not found.");
314+
).rejects.toThrow("Interface with id 'foo' not found.");
189315
});
190316

191-
it('throws if the interface is updated by another snap', () => {
317+
it('throws if the interface is updated by another snap', async () => {
192318
const rootMessenger = getRootSnapInterfaceControllerMessenger();
193319
const controllerMessenger =
194320
getRestrictedSnapInterfaceControllerMessenger(rootMessenger);
@@ -205,25 +331,25 @@ describe('SnapInterfaceController', () => {
205331
children: [input({ name: 'baz' })],
206332
});
207333

208-
const id = rootMessenger.call(
334+
const id = await rootMessenger.call(
209335
'SnapInterfaceController:createInterface',
210336
MOCK_SNAP_ID,
211337
content,
212338
);
213339

214-
expect(() =>
340+
await expect(
215341
rootMessenger.call(
216342
'SnapInterfaceController:updateInterface',
217343
'foo' as SnapId,
218344
id,
219345
newContent,
220346
),
221-
).toThrow('Interface not created by foo.');
347+
).rejects.toThrow('Interface not created by foo.');
222348
});
223349
});
224350

225351
describe('updateInterfaceState', () => {
226-
it('updates the interface state', () => {
352+
it('updates the interface state', async () => {
227353
const rootMessenger = getRootSnapInterfaceControllerMessenger();
228354
const controllerMessenger =
229355
getRestrictedSnapInterfaceControllerMessenger(rootMessenger);
@@ -237,7 +363,7 @@ describe('SnapInterfaceController', () => {
237363

238364
const newState = { foo: { bar: 'baz' } };
239365

240-
const id = rootMessenger.call(
366+
const id = await rootMessenger.call(
241367
'SnapInterfaceController:createInterface',
242368
MOCK_SNAP_ID,
243369
content,
@@ -260,7 +386,7 @@ describe('SnapInterfaceController', () => {
260386
});
261387

262388
describe('deleteInterface', () => {
263-
it('can delete an interface', () => {
389+
it('can delete an interface', async () => {
264390
const rootMessenger = getRootSnapInterfaceControllerMessenger();
265391
const controllerMessenger =
266392
getRestrictedSnapInterfaceControllerMessenger(rootMessenger);
@@ -272,7 +398,7 @@ describe('SnapInterfaceController', () => {
272398

273399
const content = form({ name: 'foo', children: [input({ name: 'bar' })] });
274400

275-
const id = rootMessenger.call(
401+
const id = await rootMessenger.call(
276402
'SnapInterfaceController:createInterface',
277403
MOCK_SNAP_ID,
278404
content,

0 commit comments

Comments
 (0)