Skip to content
Merged
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion packages/snaps-controllers/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -90,7 +90,7 @@
"@metamask/phishing-controller": "^15.0.0",
"@metamask/post-message-stream": "^10.0.0",
"@metamask/rpc-errors": "^7.0.3",
"@metamask/snaps-registry": "^3.2.3",
"@metamask/snaps-registry": "^3.3.0",
"@metamask/snaps-rpc-methods": "workspace:^",
"@metamask/snaps-sdk": "workspace:^",
"@metamask/snaps-utils": "workspace:^",
Expand Down
47 changes: 47 additions & 0 deletions packages/snaps-controllers/src/snaps/registry/json.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,10 @@ const getRegistry = (args?: Partial<JsonSnapsRegistryArgs>) => {
registry: new JsonSnapsRegistry({
messenger,
publicKey: MOCK_PUBLIC_KEY,
clientConfig: {
type: 'extension',
version: '13.9.0' as SemVerVersion,
},
...args,
}),
messenger,
Expand Down Expand Up @@ -372,6 +376,49 @@ describe('JsonSnapsRegistry', () => {
expect(result).toBe('1.0.0');
});

it('resolves to a compatible allowlisted version', async () => {
Copy link
Member

Choose a reason for hiding this comment

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

Can you add a test to make sure we resolve to 1.1.0 if the client version allows for it?

Copy link
Member Author

Choose a reason for hiding this comment

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

fetchMock
.mockResponseOnce(
JSON.stringify({
verifiedSnaps: {
[MOCK_SNAP_ID]: {
id: MOCK_SNAP_ID,
metadata: {
name: 'Mock Snap',
},
versions: {
['1.0.0' as SemVerVersion]: {
checksum: DEFAULT_SNAP_SHASUM,
},
['1.1.0' as SemVerVersion]: {
checksum: DEFAULT_SNAP_SHASUM,
clientVersions: {
extension: '>=15.0.0',
},
},
},
},
},
}),
)
.mockResponseOnce(
JSON.stringify({
...MOCK_SIGNATURE_FILE,
signature:
'0x3045022100e17cf0f34e4d521d984ed8f8492ce8a51b65178e7ba5508e01b179c5dd013c52022025e4a4008232a883048c8174e585cd89b9054eadc37330e00fd2f07a65c9bbb4',
}),
);

const { messenger } = getRegistry();
const result = await messenger.call(
'SnapsRegistry:resolveVersion',
MOCK_SNAP_ID,
'^1.0.0' as SemVerRange,
);

expect(result).toBe('1.0.0');
});

it('returns version range if snap is not on the allowlist', async () => {
fetchMock
.mockResponseOnce(
Expand Down
26 changes: 23 additions & 3 deletions packages/snaps-controllers/src/snaps/registry/json.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import {
assert,
assertIsSemVerRange,
Duration,
gtRange,
inMilliseconds,
satisfiesVersionRange,
} from '@metamask/utils';
Expand Down Expand Up @@ -39,6 +40,11 @@ type JsonSnapsRegistryUrl = {
signature: string;
};

export type ClientConfig = {
type: 'extension' | 'mobile';
version: SemVerVersion;
};

export type JsonSnapsRegistryArgs = {
messenger: SnapsRegistryMessenger;
state?: SnapsRegistryState;
Expand All @@ -47,6 +53,7 @@ export type JsonSnapsRegistryArgs = {
recentFetchThreshold?: number;
refetchOnAllowlistMiss?: boolean;
publicKey?: Hex;
clientConfig: ClientConfig;
};

export type GetResult = {
Expand Down Expand Up @@ -117,6 +124,8 @@ export class JsonSnapsRegistry extends BaseController<

readonly #publicKey: Hex;

readonly #clientConfig: ClientConfig;

readonly #fetchFunction: typeof fetch;

readonly #recentFetchThreshold: number;
Expand All @@ -133,6 +142,7 @@ export class JsonSnapsRegistry extends BaseController<
signature: SNAP_REGISTRY_SIGNATURE_URL,
},
publicKey = DEFAULT_PUBLIC_KEY,
clientConfig,
fetchFunction = globalThis.fetch.bind(undefined),
recentFetchThreshold = inMilliseconds(5, Duration.Minute),
refetchOnAllowlistMiss = true,
Expand Down Expand Up @@ -167,6 +177,7 @@ export class JsonSnapsRegistry extends BaseController<
});
this.#url = url;
this.#publicKey = publicKey;
this.#clientConfig = clientConfig;
this.#fetchFunction = fetchFunction;
this.#recentFetchThreshold = recentFetchThreshold;
this.#refetchOnAllowlistMiss = refetchOnAllowlistMiss;
Expand Down Expand Up @@ -338,11 +349,20 @@ export class JsonSnapsRegistry extends BaseController<
return versionRange;
}

const targetVersion = getTargetVersion(
Object.keys(versions) as SemVerVersion[],
versionRange,
const compatibleVersions = Object.entries(versions).reduce<SemVerVersion[]>(
(accumulator, [version, metadata]) => {
const clientRange = metadata.clientVersions?.[this.#clientConfig.type];
if (!clientRange || gtRange(this.#clientConfig.version, clientRange)) {
accumulator.push(version as SemVerVersion);
}

return accumulator;
},
[],
);

const targetVersion = getTargetVersion(compatibleVersions, versionRange);

if (!targetVersion && this.#refetchOnAllowlistMiss && !refetch) {
await this.#triggerUpdate();
return this.#resolveVersion(snapId, versionRange, true);
Expand Down
2 changes: 1 addition & 1 deletion packages/snaps-utils/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -85,7 +85,7 @@
"@metamask/permission-controller": "^12.1.0",
"@metamask/rpc-errors": "^7.0.3",
"@metamask/slip44": "^4.3.0",
"@metamask/snaps-registry": "^3.2.3",
"@metamask/snaps-registry": "^3.3.0",
"@metamask/snaps-sdk": "workspace:^",
"@metamask/superstruct": "^3.2.1",
"@metamask/utils": "^11.8.1",
Expand Down
16 changes: 8 additions & 8 deletions yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -4262,7 +4262,7 @@ __metadata:
"@metamask/phishing-controller": "npm:^15.0.0"
"@metamask/post-message-stream": "npm:^10.0.0"
"@metamask/rpc-errors": "npm:^7.0.3"
"@metamask/snaps-registry": "npm:^3.2.3"
"@metamask/snaps-registry": "npm:^3.3.0"
"@metamask/snaps-rpc-methods": "workspace:^"
"@metamask/snaps-sdk": "workspace:^"
"@metamask/snaps-utils": "workspace:^"
Expand Down Expand Up @@ -4413,15 +4413,15 @@ __metadata:
languageName: unknown
linkType: soft

"@metamask/snaps-registry@npm:^3.2.3":
version: 3.2.3
resolution: "@metamask/snaps-registry@npm:3.2.3"
"@metamask/snaps-registry@npm:^3.3.0":
version: 3.3.0
resolution: "@metamask/snaps-registry@npm:3.3.0"
dependencies:
"@metamask/superstruct": "npm:^3.1.0"
"@metamask/utils": "npm:^11.0.1"
"@metamask/superstruct": "npm:^3.2.1"
"@metamask/utils": "npm:^11.4.0"
"@noble/curves": "npm:^1.2.0"
"@noble/hashes": "npm:^1.3.2"
checksum: 10/37760f29b7aaa337d815cf0c11fa34af5093d87fdc60a3750c494cf8bae6293cd52da03e7694b467b79733052d75ec6e3781ab3590d7259a050784e5be347d12
checksum: 10/1a53ad150318cbaf703b639a3a831a6ac57f84b2266ac176e6b0d470df31ecf66f0f885256f17a7acae265ada085c904ba97f1e2cb5371e136bf90778ffaed0a
languageName: node
linkType: hard

Expand Down Expand Up @@ -4599,7 +4599,7 @@ __metadata:
"@metamask/post-message-stream": "npm:^10.0.0"
"@metamask/rpc-errors": "npm:^7.0.3"
"@metamask/slip44": "npm:^4.3.0"
"@metamask/snaps-registry": "npm:^3.2.3"
"@metamask/snaps-registry": "npm:^3.3.0"
"@metamask/snaps-sdk": "workspace:^"
"@metamask/superstruct": "npm:^3.2.1"
"@metamask/utils": "npm:^11.8.1"
Expand Down