Socket
Socket
Sign inDemoInstall

@metamask/snaps-utils

Package Overview
Dependencies
Maintainers
8
Versions
71
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

@metamask/snaps-utils - npm Package Compare versions

Comparing version 0.28.0 to 0.29.0

dist/checksum.d.ts

6

dist/caveats.d.ts

@@ -25,3 +25,7 @@ export declare enum SnapCaveatType {

*/
RpcOrigin = "rpcOrigin"
RpcOrigin = "rpcOrigin",
/**
* Caveat specifying the snap IDs that can be interacted with.
*/
SnapIds = "snapIds"
}

@@ -30,3 +30,7 @@ "use strict";

SnapCaveatType["RpcOrigin"] = "rpcOrigin";
/**
* Caveat specifying the snap IDs that can be interacted with.
*/
SnapCaveatType["SnapIds"] = "snapIds";
})(SnapCaveatType = exports.SnapCaveatType || (exports.SnapCaveatType = {}));
//# sourceMappingURL=caveats.js.map

@@ -29,2 +29,3 @@ "use strict";

if (invalidExports.length > 0) {
// eslint-disable-next-line no-console
console.warn(`Invalid snap exports detected:\n${invalidExports.join('\n')}`);

@@ -31,0 +32,0 @@ }

13

dist/fs.d.ts
import { Json } from '@metamask/utils';
import { NpmSnapFileNames } from './types';
import { VirtualFile } from './virtual-file';
/**

@@ -25,13 +25,4 @@ * Checks whether the given path string resolves to an existing directory, and

*/
export declare function readJsonFile<Type = Json>(pathString: string): Promise<Type>;
export declare function readJsonFile<Type extends Json = Json>(pathString: string): Promise<VirtualFile<Type>>;
/**
* Utility function for reading `package.json` or the Snap manifest file.
* These are assumed to be in the current working directory.
*
* @param pathString - The base path of the file to read.
* @param snapJsonFileName - The name of the file to read.
* @returns The parsed JSON file.
*/
export declare function readSnapJsonFile(pathString: string, snapJsonFileName: NpmSnapFileNames): Promise<Json>;
/**
* Gets the complete out file path from an output file name and parent

@@ -38,0 +29,0 @@ * directory path.

@@ -6,5 +6,6 @@ "use strict";

Object.defineProperty(exports, "__esModule", { value: true });
exports.validateDirPath = exports.validateFilePath = exports.validateOutfileName = exports.getOutfilePath = exports.readSnapJsonFile = exports.readJsonFile = exports.isFile = exports.isDirectory = void 0;
exports.validateDirPath = exports.validateFilePath = exports.validateOutfileName = exports.getOutfilePath = exports.readJsonFile = exports.isFile = exports.isDirectory = void 0;
const fs_1 = require("fs");
const path_1 = __importDefault(require("path"));
const virtual_file_1 = require("./virtual-file");
/**

@@ -61,26 +62,16 @@ * Checks whether the given path string resolves to an existing directory, and

}
return JSON.parse(await fs_1.promises.readFile(pathString, 'utf8'));
}
exports.readJsonFile = readJsonFile;
/**
* Utility function for reading `package.json` or the Snap manifest file.
* These are assumed to be in the current working directory.
*
* @param pathString - The base path of the file to read.
* @param snapJsonFileName - The name of the file to read.
* @returns The parsed JSON file.
*/
async function readSnapJsonFile(pathString, snapJsonFileName) {
const path = path_1.default.join(pathString, snapJsonFileName);
let file;
try {
return await readJsonFile(path);
file = await (0, virtual_file_1.readVirtualFile)(pathString, 'utf8');
}
catch (error) {
if (error.code === 'ENOENT') {
throw new Error(`Could not find '${path}'. Please ensure that the file exists.`);
throw new Error(`Could not find '${pathString}'. Please ensure that the file exists.`);
}
throw error;
}
file.result = JSON.parse(file.toString());
return file;
}
exports.readSnapJsonFile = readSnapJsonFile;
exports.readJsonFile = readJsonFile;
/**

@@ -87,0 +78,0 @@ * Gets the complete out file path from an output file name and parent

@@ -1,2 +0,1 @@

import type { StreamProvider } from '@metamask/providers';
import { Component } from '@metamask/snaps-ui';

@@ -6,8 +5,2 @@ import { Json, JsonRpcRequest } from '@metamask/utils';

/**
* The global `snap` object. This is injected into the global scope of a snap.
*/
export declare type SnapsGlobalObject = {
request: StreamProvider['request'];
};
/**
* The `onRpcRequest` handler. This is called whenever a JSON-RPC request is

@@ -14,0 +7,0 @@ * made to the snap.

export * from './caveats';
export * from './checksum';
export * from './cronjob';

@@ -10,2 +11,3 @@ export * from './deep-clone';

export * from './json-rpc';
export * from './logging';
export * from './manifest/index.browser';

@@ -12,0 +14,0 @@ export * from './namespace';

@@ -18,2 +18,3 @@ "use strict";

__exportStar(require("./caveats"), exports);
__exportStar(require("./checksum"), exports);
__exportStar(require("./cronjob"), exports);

@@ -27,2 +28,3 @@ __exportStar(require("./deep-clone"), exports);

__exportStar(require("./json-rpc"), exports);
__exportStar(require("./logging"), exports);
__exportStar(require("./manifest/index.browser"), exports);

@@ -29,0 +31,0 @@ __exportStar(require("./namespace"), exports);

export * from './caveats';
export * from './cronjob';
export * from './checksum';
export * from './deep-clone';

@@ -12,2 +13,3 @@ export * from './default-endowments';

export * from './json-rpc';
export * from './logging';
export * from './manifest';

@@ -14,0 +16,0 @@ export * from './mock';

@@ -19,2 +19,3 @@ "use strict";

__exportStar(require("./cronjob"), exports);
__exportStar(require("./checksum"), exports);
__exportStar(require("./deep-clone"), exports);

@@ -29,2 +30,3 @@ __exportStar(require("./default-endowments"), exports);

__exportStar(require("./json-rpc"), exports);
__exportStar(require("./logging"), exports);
__exportStar(require("./manifest"), exports);

@@ -31,0 +33,0 @@ __exportStar(require("./mock"), exports);

import { Json } from '@metamask/utils';
import { ProgrammaticallyFixableSnapError } from '../snaps';
import { NpmSnapPackageJson, SnapFiles } from '../types';
import { SnapFiles } from '../types';
import { VirtualFile } from '../virtual-file';
import { SnapManifest } from './validation';

@@ -46,3 +47,3 @@ /**

*/
export declare function fixManifest(snapFiles: SnapFiles, error: ProgrammaticallyFixableSnapError): SnapManifest;
export declare function fixManifest(snapFiles: SnapFiles, error: ProgrammaticallyFixableSnapError): VirtualFile<SnapManifest>;
/**

@@ -54,6 +55,16 @@ * Given an unvalidated Snap manifest, attempts to extract the location of the

* @param manifest - The unvalidated Snap manifest file contents.
* @param sourceCode - Override source code for plugins.
* @returns The contents of the bundle file, if any.
*/
export declare function getSnapSourceCode(basePath: string, manifest: Json): Promise<string | undefined>;
export declare function getSnapSourceCode(basePath: string, manifest: Json, sourceCode?: string): Promise<VirtualFile | undefined>;
/**
* Given an unvalidated Snap manifest, attempts to extract the location of the
* icon and read the file.
*
* @param basePath - The path to the folder with the manifest files.
* @param manifest - The unvalidated Snap manifest file contents.
* @returns The contents of the icon, if any.
*/
export declare function getSnapIcon(basePath: string, manifest: Json): Promise<VirtualFile | undefined>;
/**
* Sorts the given manifest in our preferred sort order and removes the

@@ -74,5 +85,4 @@ * `repository` field if it is falsy (it may be `null`).

* @param snapFiles.sourceCode - The Snap's source code.
* @returns A tuple containing the validated snap manifest, snap source code,
* and `package.json`.
* @param snapFiles.svgIcon - The Snap's optional icon.
*/
export declare function validateNpmSnapManifest({ manifest, packageJson, sourceCode, }: SnapFiles): [SnapManifest, string, NpmSnapPackageJson];
export declare function validateNpmSnapManifest({ manifest, packageJson, sourceCode, svgIcon, }: SnapFiles): void;

@@ -17,3 +17,3 @@ "use strict";

Object.defineProperty(exports, "__esModule", { value: true });
exports.validateNpmSnapManifest = exports.getWritableManifest = exports.getSnapSourceCode = exports.fixManifest = exports.checkManifest = void 0;
exports.validateNpmSnapManifest = exports.getWritableManifest = exports.getSnapIcon = exports.getSnapSourceCode = exports.fixManifest = exports.checkManifest = void 0;
const utils_1 = require("@metamask/utils");

@@ -28,2 +28,3 @@ const fast_deep_equal_1 = __importDefault(require("fast-deep-equal"));

const types_1 = require("../types");
const virtual_file_1 = require("../virtual-file");
const MANIFEST_SORT_ORDER = {

@@ -50,18 +51,14 @@ version: 1,

async function checkManifest(basePath, writeManifest = true, sourceCode) {
var _a, _b, _c;
const warnings = [];
const errors = [];
let updated = false;
const unvalidatedManifest = await (0, fs_2.readSnapJsonFile)(basePath, types_1.NpmSnapFileNames.Manifest);
const iconPath = unvalidatedManifest && typeof unvalidatedManifest === 'object'
? /* istanbul ignore next */
(_c = (_b = (_a = unvalidatedManifest.source) === null || _a === void 0 ? void 0 : _a.location) === null || _b === void 0 ? void 0 : _b.npm) === null || _c === void 0 ? void 0 : _c.iconPath
: /* istanbul ignore next */
undefined;
const manifestPath = path_1.default.join(basePath, types_1.NpmSnapFileNames.Manifest);
const manifestFile = await (0, fs_2.readJsonFile)(manifestPath);
const unvalidatedManifest = manifestFile.result;
const packageFile = await (0, fs_2.readJsonFile)(path_1.default.join(basePath, types_1.NpmSnapFileNames.PackageJson));
const snapFiles = {
manifest: unvalidatedManifest,
packageJson: await (0, fs_2.readSnapJsonFile)(basePath, types_1.NpmSnapFileNames.PackageJson),
sourceCode: sourceCode !== null && sourceCode !== void 0 ? sourceCode : (await getSnapSourceCode(basePath, unvalidatedManifest)),
svgIcon: iconPath &&
(await fs_1.promises.readFile(path_1.default.join(basePath, iconPath), 'utf8')),
manifest: manifestFile,
packageJson: packageFile,
sourceCode: await getSnapSourceCode(basePath, unvalidatedManifest, sourceCode),
svgIcon: await getSnapIcon(basePath, unvalidatedManifest),
};

@@ -107,5 +104,6 @@ let manifest;

}
// TypeScript doesn't see that the 'manifest' variable must be of type
// SnapManifest at this point, so we cast it.
const validatedManifest = manifest;
// TypeScript assumes `manifest` can still be undefined, that is not the case.
// But we assert to keep TypeScript happy.
(0, utils_1.assert)(manifest);
const validatedManifest = manifest.result;
// Check presence of recommended keys

@@ -121,3 +119,6 @@ const recommendedFields = ['repository'];

try {
await fs_1.promises.writeFile(path_1.default.join(basePath, types_1.NpmSnapFileNames.Manifest), `${JSON.stringify(getWritableManifest(validatedManifest), null, 2)}\n`);
const newManifest = `${JSON.stringify(getWritableManifest(validatedManifest), null, 2)}\n`;
if (updated || newManifest !== manifestFile.value) {
await fs_1.promises.writeFile(path_1.default.join(basePath, types_1.NpmSnapFileNames.Manifest), newManifest);
}
}

@@ -143,18 +144,19 @@ catch (error) {

function fixManifest(snapFiles, error) {
const { manifest, packageJson, sourceCode } = snapFiles;
const manifestCopy = (0, deep_clone_1.deepClone)(manifest);
const { manifest, packageJson } = snapFiles;
const clonedFile = manifest.clone();
const manifestCopy = clonedFile.result;
switch (error.reason) {
case types_1.SnapValidationFailureReason.NameMismatch:
manifestCopy.source.location.npm.packageName = packageJson.name;
manifestCopy.source.location.npm.packageName = packageJson.result.name;
break;
case types_1.SnapValidationFailureReason.VersionMismatch:
manifestCopy.version = packageJson.version;
manifestCopy.version = packageJson.result.version;
break;
case types_1.SnapValidationFailureReason.RepositoryMismatch:
manifestCopy.repository = packageJson.repository
? (0, deep_clone_1.deepClone)(packageJson.repository)
manifestCopy.repository = packageJson.result.repository
? (0, deep_clone_1.deepClone)(packageJson.result.repository)
: undefined;
break;
case types_1.SnapValidationFailureReason.ShasumMismatch:
manifestCopy.source.shasum = (0, snaps_1.getSnapSourceShasum)(sourceCode);
manifestCopy.source.shasum = (0, snaps_1.getSnapChecksum)(snapFiles);
break;

@@ -165,3 +167,5 @@ /* istanbul ignore next */

}
return manifestCopy;
clonedFile.result = manifestCopy;
clonedFile.value = JSON.stringify(manifestCopy);
return clonedFile;
}

@@ -175,21 +179,56 @@ exports.fixManifest = fixManifest;

* @param manifest - The unvalidated Snap manifest file contents.
* @param sourceCode - Override source code for plugins.
* @returns The contents of the bundle file, if any.
*/
async function getSnapSourceCode(basePath, manifest) {
async function getSnapSourceCode(basePath, manifest, sourceCode) {
var _a, _b, _c;
if (manifest && typeof manifest === 'object' && !Array.isArray(manifest)) {
const sourceFilePath = (_c = (_b = (_a = manifest.source) === null || _a === void 0 ? void 0 : _a.location) === null || _b === void 0 ? void 0 : _b.npm) === null || _c === void 0 ? void 0 : _c.filePath;
try {
return sourceFilePath
? await fs_1.promises.readFile(path_1.default.join(basePath, sourceFilePath), 'utf8')
: undefined;
}
catch (error) {
throw new Error(`Failed to read Snap bundle file: ${error.message}`);
}
if (!(0, utils_1.isPlainObject)(manifest)) {
return undefined;
}
return undefined;
const sourceFilePath = (_c = (_b = (_a = manifest.source) === null || _a === void 0 ? void 0 : _a.location) === null || _b === void 0 ? void 0 : _b.npm) === null || _c === void 0 ? void 0 : _c.filePath;
if (!sourceFilePath) {
return undefined;
}
if (sourceCode) {
return new virtual_file_1.VirtualFile({
path: path_1.default.join(basePath, sourceFilePath),
value: sourceCode,
});
}
try {
const virtualFile = await (0, virtual_file_1.readVirtualFile)(path_1.default.join(basePath, sourceFilePath), 'utf8');
return virtualFile;
}
catch (error) {
throw new Error(`Failed to read Snap bundle file: ${error.message}`);
}
}
exports.getSnapSourceCode = getSnapSourceCode;
/**
* Given an unvalidated Snap manifest, attempts to extract the location of the
* icon and read the file.
*
* @param basePath - The path to the folder with the manifest files.
* @param manifest - The unvalidated Snap manifest file contents.
* @returns The contents of the icon, if any.
*/
async function getSnapIcon(basePath, manifest) {
var _a, _b, _c;
if (!(0, utils_1.isPlainObject)(manifest)) {
return undefined;
}
const iconPath = (_c = (_b = (_a = manifest.source) === null || _a === void 0 ? void 0 : _a.location) === null || _b === void 0 ? void 0 : _b.npm) === null || _c === void 0 ? void 0 : _c.iconPath;
if (!iconPath) {
return undefined;
}
try {
const virtualFile = await (0, virtual_file_1.readVirtualFile)(path_1.default.join(basePath, iconPath), 'utf8');
return virtualFile;
}
catch (error) {
throw new Error(`Failed to read Snap icon file: ${error.message}`);
}
}
exports.getSnapIcon = getSnapIcon;
/**
* Sorts the given manifest in our preferred sort order and removes the

@@ -218,12 +257,11 @@ * `repository` field if it is falsy (it may be `null`).

* @param snapFiles.sourceCode - The Snap's source code.
* @returns A tuple containing the validated snap manifest, snap source code,
* and `package.json`.
* @param snapFiles.svgIcon - The Snap's optional icon.
*/
function validateNpmSnapManifest({ manifest, packageJson, sourceCode, }) {
const packageJsonName = packageJson.name;
const packageJsonVersion = packageJson.version;
const packageJsonRepository = packageJson.repository;
const manifestPackageName = manifest.source.location.npm.packageName;
const manifestPackageVersion = manifest.version;
const manifestRepository = manifest.repository;
function validateNpmSnapManifest({ manifest, packageJson, sourceCode, svgIcon, }) {
const packageJsonName = packageJson.result.name;
const packageJsonVersion = packageJson.result.version;
const packageJsonRepository = packageJson.result.repository;
const manifestPackageName = manifest.result.source.location.npm.packageName;
const manifestPackageVersion = manifest.result.version;
const manifestRepository = manifest.result.repository;
if (packageJsonName !== manifestPackageName) {

@@ -242,6 +280,5 @@ throw new snaps_1.ProgrammaticallyFixableSnapError(`"${types_1.NpmSnapFileNames.Manifest}" npm package name ("${manifestPackageName}") does not match the "${types_1.NpmSnapFileNames.PackageJson}" "name" field ("${packageJsonName}").`, types_1.SnapValidationFailureReason.NameMismatch);

}
(0, snaps_1.validateSnapShasum)(manifest, sourceCode, `"${types_1.NpmSnapFileNames.Manifest}" "shasum" field does not match computed shasum.`);
return [manifest, sourceCode, packageJson];
(0, snaps_1.validateSnapShasum)({ manifest, sourceCode, svgIcon }, `"${types_1.NpmSnapFileNames.Manifest}" "shasum" field does not match computed shasum.`);
}
exports.validateNpmSnapManifest = validateNpmSnapManifest;
//# sourceMappingURL=manifest.js.map

@@ -197,2 +197,3 @@ import { Infer, Struct } from 'superstruct';

source: {
shasum: string;
location: {

@@ -206,3 +207,2 @@ npm: {

};
shasum: string;
};

@@ -273,2 +273,3 @@ initialPermissions: {

source: Struct<{
shasum: string;
location: {

@@ -282,3 +283,2 @@ npm: {

};
shasum: string;
}, {

@@ -300,4 +300,4 @@ shasum: Struct<string, null>;

}, {
filePath: Struct<string, unknown>;
iconPath: Struct<string | undefined, unknown>;
filePath: Struct<string, null>;
iconPath: Struct<string | undefined, null>;
packageName: Struct<string, null>;

@@ -304,0 +304,0 @@ registry: Struct<"https://registry.npmjs.org" | "https://registry.npmjs.org/", null>;

@@ -10,3 +10,2 @@ "use strict";

const namespace_1 = require("../namespace");
const path_1 = require("../path");
const types_1 = require("../types");

@@ -72,4 +71,2 @@ // BIP-43 purposes that cannot be used for entropy derivation. These are in the

});
/* eslint-enable @typescript-eslint/naming-convention */
const relativePath = (struct) => (0, superstruct_1.coerce)(struct, struct, (value) => (0, path_1.normalizeRelative)(value));
exports.SnapManifestStruct = (0, superstruct_1.object)({

@@ -87,4 +84,4 @@ version: utils_1.VersionStruct,

npm: (0, superstruct_1.object)({
filePath: relativePath((0, superstruct_1.size)((0, superstruct_1.string)(), 1, Infinity)),
iconPath: (0, superstruct_1.optional)(relativePath((0, superstruct_1.size)((0, superstruct_1.string)(), 1, Infinity))),
filePath: (0, superstruct_1.size)((0, superstruct_1.string)(), 1, Infinity),
iconPath: (0, superstruct_1.optional)((0, superstruct_1.size)((0, superstruct_1.string)(), 1, Infinity)),
packageName: types_1.NameStruct,

@@ -91,0 +88,0 @@ registry: (0, superstruct_1.union)([

@@ -97,4 +97,4 @@ import { AssertionErrorConstructor } from '@metamask/utils';

export declare const SessionNamespaceStruct: import("superstruct").Struct<{
chains: string[];
accounts: string[];
chains: string[];
methods?: string[] | undefined;

@@ -128,4 +128,4 @@ events?: string[] | undefined;

namespaces: Record<string, {
chains: string[];
accounts: string[];
chains: string[];
methods?: string[] | undefined;

@@ -136,4 +136,4 @@ events?: string[] | undefined;

namespaces: import("superstruct").Struct<Record<string, {
chains: string[];
accounts: string[];
chains: string[];
methods?: string[] | undefined;

@@ -140,0 +140,0 @@ events?: string[] | undefined;

@@ -38,3 +38,3 @@ "use strict";

try {
(0, validation_1.assertIsSnapManifest)(manifest);
(0, validation_1.assertIsSnapManifest)(manifest.result);
}

@@ -45,3 +45,3 @@ catch (error) {

const validatedManifest = manifest;
const { iconPath } = validatedManifest.source.location.npm;
const { iconPath } = validatedManifest.result.source.location.npm;
if (iconPath && !svgIcon) {

@@ -51,3 +51,3 @@ throw new Error(`Missing file "${iconPath}".`);

try {
(0, types_1.assertIsNpmSnapPackageJson)(packageJson);
(0, types_1.assertIsNpmSnapPackageJson)(packageJson.result);
}

@@ -62,5 +62,6 @@ catch (error) {

sourceCode,
svgIcon,
});
if (svgIcon) {
if (Buffer.byteLength(svgIcon, 'utf8') > exports.SVG_MAX_BYTE_SIZE) {
if (Buffer.byteLength(svgIcon.value, 'utf8') > exports.SVG_MAX_BYTE_SIZE) {
throw new Error(`${errorPrefix !== null && errorPrefix !== void 0 ? errorPrefix : ''}The specified SVG icon exceeds the maximum size of ${exports.SVG_MAX_BYTE_SIZE_TEXT}.`);

@@ -67,0 +68,0 @@ }

@@ -58,3 +58,4 @@ "use strict";

function breakTokensTemplateLiteral(value) {
// @ts-expect-error `matchAll` is not available in ES2017, but this code
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-ignore `matchAll` is not available in ES2017, but this code
// should only be used in environments where the function is supported.

@@ -61,0 +62,0 @@ const matches = Array.from(value.matchAll(TOKEN_REGEX));

@@ -0,1 +1,2 @@

import { SubjectPermissions, PermissionConstraint } from '@metamask/permission-controller';
import { BlockReason } from '@metamask/snaps-registry';

@@ -6,5 +7,3 @@ import { Json, SemVerVersion } from '@metamask/utils';

import { SnapManifest, SnapPermissions } from './manifest/validation';
import { SnapId, SnapIdPrefixes, SnapValidationFailureReason } from './types';
export declare const SNAP_PREFIX = "wallet_snap_";
export declare const SNAP_PREFIX_REGEX: RegExp;
import { SnapFiles, SnapId, SnapIdPrefixes, SnapsPermissionRequest, SnapValidationFailureReason } from './types';
export declare const PROPOSED_NAME_REGEX: RegExp;

@@ -84,6 +83,2 @@ /**

/**
* The name of the permission used to invoke the Snap.
*/
permissionName: string;
/**
* The current status of the Snap, e.g. whether it's running or stopped.

@@ -102,3 +97,3 @@ */

};
export declare type TruncatedSnapFields = 'id' | 'initialPermissions' | 'permissionName' | 'version' | 'enabled' | 'blocked';
export declare type TruncatedSnapFields = 'id' | 'initialPermissions' | 'version' | 'enabled' | 'blocked';
/**

@@ -122,18 +117,17 @@ * A {@link Snap} object with the fields that are relevant to an external

/**
* Calculates the Base64-encoded SHA-256 digest of a Snap source code string.
* Calculates the Base64-encoded SHA-256 digest of all required Snap files.
*
* @param sourceCode - The UTF-8 string source code of a Snap.
* @param files - All required Snap files to be included in the checksum.
* @returns The Base64-encoded SHA-256 digest of the source code.
*/
export declare function getSnapSourceShasum(sourceCode: string): string;
export declare function getSnapChecksum(files: Pick<SnapFiles, 'manifest' | 'sourceCode' | 'svgIcon'>): string;
export declare type ValidatedSnapId = `local:${string}` | `npm:${string}`;
/**
* Checks whether the `source.shasum` property of a Snap manifest matches the
* shasum of a snap source code string.
* shasum of the snap.
*
* @param manifest - The manifest whose shasum to validate.
* @param sourceCode - The source code of the snap.
* @param files - All required Snap files to be included in the checksum.
* @param errorMessage - The error message to throw if validation fails.
*/
export declare function validateSnapShasum(manifest: SnapManifest, sourceCode: string, errorMessage?: string): void;
export declare function validateSnapShasum(files: Pick<SnapFiles, 'manifest' | 'sourceCode' | 'svgIcon'>, errorMessage?: string): void;
export declare const LOCALHOST_HOSTNAMES: readonly ["localhost", "127.0.0.1", "[::1]"];

@@ -151,9 +145,2 @@ export declare const LocalSnapIdStruct: Struct<string, null>;

/**
* Computes the permission name of a snap from its snap ID.
*
* @param snapId - The snap ID.
* @returns The permission name corresponding to the given snap ID.
*/
export declare function getSnapPermissionName(snapId: string): string;
/**
* Asserts the provided object is a snapId with a supported prefix.

@@ -172,1 +159,17 @@ *

export declare function isCaipChainId(chainId: unknown): chainId is string;
/**
* Utility function to check if an origin has permission (and caveat) for a particular snap.
*
* @param permissions - An origin's permissions object.
* @param snapId - The id of the snap.
* @returns A boolean based on if an origin has the specified snap.
*/
export declare function isSnapPermitted(permissions: SubjectPermissions<PermissionConstraint>, snapId: SnapId): boolean;
/**
* Checks whether the passed in requestedPermissions is a valid
* permission request for a `wallet_snap` permission.
*
* @param requestedPermissions - The requested permissions.
* @throws If the criteria is not met.
*/
export declare function verifyRequestedSnapPermissions(requestedPermissions: unknown): asserts requestedPermissions is SnapsPermissionRequest;

@@ -6,11 +6,11 @@ "use strict";

Object.defineProperty(exports, "__esModule", { value: true });
exports.isCaipChainId = exports.validateSnapId = exports.getSnapPermissionName = exports.getSnapPrefix = exports.HttpSnapIdStruct = exports.NpmSnapIdStruct = exports.LocalSnapIdStruct = exports.LOCALHOST_HOSTNAMES = exports.validateSnapShasum = exports.getSnapSourceShasum = exports.ProgrammaticallyFixableSnapError = exports.SnapStatusEvents = exports.SnapStatus = exports.PROPOSED_NAME_REGEX = exports.SNAP_PREFIX_REGEX = exports.SNAP_PREFIX = void 0;
exports.verifyRequestedSnapPermissions = exports.isSnapPermitted = exports.isCaipChainId = exports.validateSnapId = exports.getSnapPrefix = exports.HttpSnapIdStruct = exports.NpmSnapIdStruct = exports.LocalSnapIdStruct = exports.LOCALHOST_HOSTNAMES = exports.validateSnapShasum = exports.getSnapChecksum = exports.ProgrammaticallyFixableSnapError = exports.SnapStatusEvents = exports.SnapStatus = exports.PROPOSED_NAME_REGEX = void 0;
const utils_1 = require("@metamask/utils");
const sha256_1 = require("@noble/hashes/sha256");
const base_1 = require("@scure/base");
const fast_json_stable_stringify_1 = __importDefault(require("fast-json-stable-stringify"));
const superstruct_1 = require("superstruct");
const validate_npm_package_name_1 = __importDefault(require("validate-npm-package-name"));
const caveats_1 = require("./caveats");
const checksum_1 = require("./checksum");
const types_1 = require("./types");
exports.SNAP_PREFIX = 'wallet_snap_';
exports.SNAP_PREFIX_REGEX = new RegExp(`^${exports.SNAP_PREFIX}`, 'u');
// This RegEx matches valid npm package names (with some exceptions) and space-

@@ -53,21 +53,36 @@ // separated alphanumerical words, optionally with dashes and underscores.

/**
* Calculates the Base64-encoded SHA-256 digest of a Snap source code string.
* Gets a checksummable manifest by removing the shasum property and reserializing the JSON using a deterministic algorithm.
*
* @param sourceCode - The UTF-8 string source code of a Snap.
* @param manifest - The manifest itself.
* @returns A virtual file containing the checksummable manifest.
*/
function getChecksummableManifest(manifest) {
const manifestCopy = manifest.clone();
delete manifestCopy.result.source.shasum;
// We use fast-json-stable-stringify to deterministically serialize the JSON
// This is required before checksumming so we get reproducible checksums across platforms etc
manifestCopy.value = (0, fast_json_stable_stringify_1.default)(manifestCopy.result);
return manifestCopy;
}
/**
* Calculates the Base64-encoded SHA-256 digest of all required Snap files.
*
* @param files - All required Snap files to be included in the checksum.
* @returns The Base64-encoded SHA-256 digest of the source code.
*/
function getSnapSourceShasum(sourceCode) {
return base_1.base64.encode((0, sha256_1.sha256)(sourceCode));
function getSnapChecksum(files) {
const { manifest, sourceCode, svgIcon } = files;
const all = [getChecksummableManifest(manifest), sourceCode, svgIcon].filter((file) => file !== undefined);
return base_1.base64.encode((0, checksum_1.checksumFiles)(all));
}
exports.getSnapSourceShasum = getSnapSourceShasum;
exports.getSnapChecksum = getSnapChecksum;
/**
* Checks whether the `source.shasum` property of a Snap manifest matches the
* shasum of a snap source code string.
* shasum of the snap.
*
* @param manifest - The manifest whose shasum to validate.
* @param sourceCode - The source code of the snap.
* @param files - All required Snap files to be included in the checksum.
* @param errorMessage - The error message to throw if validation fails.
*/
function validateSnapShasum(manifest, sourceCode, errorMessage = 'Invalid Snap manifest: manifest shasum does not match computed shasum.') {
if (manifest.source.shasum !== getSnapSourceShasum(sourceCode)) {
function validateSnapShasum(files, errorMessage = 'Invalid Snap manifest: manifest shasum does not match computed shasum.') {
if (files.manifest.result.source.shasum !== getSnapChecksum(files)) {
throw new ProgrammaticallyFixableSnapError(errorMessage, types_1.SnapValidationFailureReason.ShasumMismatch);

@@ -136,12 +151,2 @@ }

/**
* Computes the permission name of a snap from its snap ID.
*
* @param snapId - The snap ID.
* @returns The permission name corresponding to the given snap ID.
*/
function getSnapPermissionName(snapId) {
return exports.SNAP_PREFIX + snapId;
}
exports.getSnapPermissionName = getSnapPermissionName;
/**
* Asserts the provided object is a snapId with a supported prefix.

@@ -175,2 +180,33 @@ *

exports.isCaipChainId = isCaipChainId;
/**
* Utility function to check if an origin has permission (and caveat) for a particular snap.
*
* @param permissions - An origin's permissions object.
* @param snapId - The id of the snap.
* @returns A boolean based on if an origin has the specified snap.
*/
function isSnapPermitted(permissions, snapId) {
var _a, _b, _c, _d;
return Boolean((_d = ((_c = (_b = (_a = permissions === null || permissions === void 0 ? void 0 : permissions.wallet_snap) === null || _a === void 0 ? void 0 : _a.caveats) === null || _b === void 0 ? void 0 : _b.find((caveat) => caveat.type === caveats_1.SnapCaveatType.SnapIds)) !== null && _c !== void 0 ? _c : {}).value) === null || _d === void 0 ? void 0 : _d[snapId]);
}
exports.isSnapPermitted = isSnapPermitted;
/**
* Checks whether the passed in requestedPermissions is a valid
* permission request for a `wallet_snap` permission.
*
* @param requestedPermissions - The requested permissions.
* @throws If the criteria is not met.
*/
function verifyRequestedSnapPermissions(requestedPermissions) {
(0, utils_1.assert)((0, utils_1.isObject)(requestedPermissions), 'Requested permissions must be an object.');
const { wallet_snap: walletSnapPermission } = requestedPermissions;
(0, utils_1.assert)((0, utils_1.isObject)(walletSnapPermission), 'wallet_snap is missing from the requested permissions.');
const { caveats } = walletSnapPermission;
(0, utils_1.assert)(Array.isArray(caveats) && caveats.length === 1, 'wallet_snap must have a caveat property with a single-item array value.');
const [caveat] = caveats;
(0, utils_1.assert)((0, utils_1.isObject)(caveat) &&
caveat.type === caveats_1.SnapCaveatType.SnapIds &&
(0, utils_1.isObject)(caveat.value), `The requested permissions do not have a valid ${caveats_1.SnapCaveatType.SnapIds} caveat.`);
}
exports.verifyRequestedSnapPermissions = verifyRequestedSnapPermissions;
//# sourceMappingURL=snaps.js.map
import { Json } from '@metamask/utils';
import { Infer, Struct } from 'superstruct';
import { SnapCaveatType } from './caveats';
import { SnapFunctionExports, SnapKeyring as Keyring } from './handlers';
import { SnapManifest } from './manifest';
import { VirtualFile } from './virtual-file';
export declare enum NpmSnapFileNames {

@@ -49,6 +51,6 @@ PackageJson = "package.json",

export declare type UnvalidatedSnapFiles = {
manifest?: Json;
packageJson?: Json;
sourceCode?: string;
svgIcon?: string;
manifest?: VirtualFile<Json>;
packageJson?: VirtualFile<Json>;
sourceCode?: VirtualFile;
svgIcon?: VirtualFile;
};

@@ -60,6 +62,6 @@ /**

export declare type SnapFiles = {
manifest: SnapManifest;
packageJson: NpmSnapPackageJson;
sourceCode: string;
svgIcon?: string;
manifest: VirtualFile<SnapManifest>;
packageJson: VirtualFile<NpmSnapPackageJson>;
sourceCode: VirtualFile;
svgIcon?: VirtualFile;
};

@@ -122,2 +124,13 @@ /**

export declare function isValidUrl(url: unknown, opts?: UriOptions<any>): url is string | URL;
export declare const WALLET_SNAP_PERMISSION_KEY = "wallet_snap";
export declare type SnapsPermissionRequest = {
[WALLET_SNAP_PERMISSION_KEY]: {
caveats: [
{
type: SnapCaveatType.SnapIds;
value: Record<string, Json>;
}
];
};
};
export {};
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.isValidUrl = exports.uri = exports.SNAP_EXPORT_NAMES = exports.HandlerType = exports.SNAP_STREAM_NAMES = exports.SnapValidationFailureReason = exports.SnapIdPrefixes = exports.assertIsNpmSnapPackageJson = exports.isNpmSnapPackageJson = exports.NpmSnapPackageJsonStruct = exports.NameStruct = exports.NpmSnapFileNames = void 0;
exports.WALLET_SNAP_PERMISSION_KEY = exports.isValidUrl = exports.uri = exports.SNAP_EXPORT_NAMES = exports.HandlerType = exports.SNAP_STREAM_NAMES = exports.SnapValidationFailureReason = exports.SnapIdPrefixes = exports.assertIsNpmSnapPackageJson = exports.isNpmSnapPackageJson = exports.NpmSnapPackageJsonStruct = exports.NameStruct = exports.NpmSnapFileNames = void 0;
const utils_1 = require("@metamask/utils");

@@ -101,2 +101,4 @@ const superstruct_1 = require("superstruct");

exports.isValidUrl = isValidUrl;
// redefining here to avoid circular dependency
exports.WALLET_SNAP_PERMISSION_KEY = 'wallet_snap';
//# sourceMappingURL=types.js.map
/// <reference types="node" />
/// <reference types="node" />
import fsPromises from 'fs/promises';
import { promises as fsPromises } from 'fs';
import { VirtualFile } from './VirtualFile';

@@ -5,0 +5,0 @@ /**

"use strict";
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.writeVirtualFile = exports.readVirtualFile = void 0;
const promises_1 = __importDefault(require("fs/promises"));
const fs_1 = require("fs");
const VirtualFile_1 = require("./VirtualFile");

@@ -19,3 +16,3 @@ /**

path,
value: await promises_1.default.readFile(path, { encoding }),
value: await fs_1.promises.readFile(path, { encoding }),
});

@@ -31,5 +28,5 @@ }

async function writeVirtualFile(vfile, options) {
return promises_1.default.writeFile(vfile.path, vfile.value, options);
return fs_1.promises.writeFile(vfile.path, vfile.value, options);
}
exports.writeVirtualFile = writeVirtualFile;
//# sourceMappingURL=toVirtualFile.js.map
{
"name": "@metamask/snaps-utils",
"version": "0.28.0",
"version": "0.29.0",
"repository": {

@@ -55,5 +55,6 @@ "type": "git",

"@babel/types": "^7.18.7",
"@metamask/permission-controller": "^2.0.0",
"@metamask/providers": "^10.2.1",
"@metamask/snaps-registry": "^1.0.0",
"@metamask/snaps-ui": "^0.28.0",
"@metamask/snaps-ui": "^0.29.0",
"@metamask/utils": "^3.4.1",

@@ -65,2 +66,3 @@ "@noble/hashes": "^1.1.3",

"fast-deep-equal": "^3.1.3",
"fast-json-stable-stringify": "^2.1.0",
"rfdc": "^1.3.0",

@@ -79,3 +81,3 @@ "semver": "^7.3.7",

"@metamask/eslint-config-typescript": "^11.0.0",
"@metamask/key-tree": "^6.2.0",
"@metamask/key-tree": "^6.2.1",
"@metamask/post-message-stream": "^6.1.0",

@@ -82,0 +84,0 @@ "@types/jest": "^27.5.1",

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc