@metamask/snaps-utils
Version:
A collection of utilities for MetaMask Snaps
131 lines • 5.55 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
exports.assertIsJsonRpcSuccess = exports.isOriginAllowed = exports.assertIsKeyringOrigins = exports.KeyringOriginsStruct = exports.assertIsRpcOrigins = exports.RpcOriginsStruct = void 0;
const permission_controller_1 = require("@metamask/permission-controller");
const superstruct_1 = require("@metamask/superstruct");
const utils_1 = require("@metamask/utils");
const AllowedOriginsStruct = (0, superstruct_1.array)((0, superstruct_1.refine)((0, superstruct_1.string)(), 'Allowed origin', (value) => {
const wildcards = value.split('*').length - 1;
if (wildcards > 2) {
return 'No more than two wildcards ("*") are allowed in an origin specifier.';
}
return true;
}));
exports.RpcOriginsStruct = (0, superstruct_1.refine)((0, superstruct_1.object)({
dapps: (0, superstruct_1.optional)((0, superstruct_1.boolean)()),
snaps: (0, superstruct_1.optional)((0, superstruct_1.boolean)()),
allowedOrigins: (0, superstruct_1.optional)(AllowedOriginsStruct),
}), 'RPC origins', (value) => {
const hasOrigins = Boolean(value.snaps === true ||
value.dapps === true ||
(value.allowedOrigins && value.allowedOrigins.length > 0));
if (hasOrigins) {
return true;
}
return 'Must specify at least one JSON-RPC origin.';
});
/**
* Asserts that the given value is a valid {@link RpcOrigins} object.
*
* @param value - The value to assert.
* @param ErrorWrapper - An optional error wrapper to use. Defaults to
* {@link AssertionError}.
* @throws If the value is not a valid {@link RpcOrigins} object.
*/
function assertIsRpcOrigins(value, ErrorWrapper) {
(0, utils_1.assertStruct)(value, exports.RpcOriginsStruct, 'Invalid JSON-RPC origins', ErrorWrapper);
}
exports.assertIsRpcOrigins = assertIsRpcOrigins;
exports.KeyringOriginsStruct = (0, superstruct_1.object)({
allowedOrigins: (0, superstruct_1.optional)(AllowedOriginsStruct),
});
/**
* Assert that the given value is a valid {@link KeyringOrigins} object.
*
* @param value - The value to assert.
* @param ErrorWrapper - An optional error wrapper to use. Defaults to
* {@link AssertionError}.
* @throws If the value is not a valid {@link KeyringOrigins} object.
*/
function assertIsKeyringOrigins(value, ErrorWrapper) {
(0, utils_1.assertStruct)(value, exports.KeyringOriginsStruct, 'Invalid keyring origins', ErrorWrapper);
}
exports.assertIsKeyringOrigins = assertIsKeyringOrigins;
/**
* Create regular expression for matching against an origin while allowing wildcards.
*
* The "*" symbol is treated as a wildcard and will match 0 or more characters.
*
* @param matcher - The string to create the regular expression with.
* @returns The regular expression.
*/
function createOriginRegExp(matcher) {
// Escape potential Regex characters
const escaped = matcher.replace(/[.*+?^${}()|[\]\\]/gu, '\\$&');
// Support wildcards
const regex = escaped.replace(/\\\*/gu, '.*');
return RegExp(`^${regex}$`, 'u');
}
/**
* Check whether an origin is allowed or not using a matcher string.
*
* The matcher string may be a specific origin to match or include wildcards.
* The "*" symbol is treated as a wildcard and will match 0 or more characters.
* Note: this means that https://*metamask.io matches both https://metamask.io
* and https://snaps.metamask.io.
*
* @param matcher - The matcher string.
* @param origin - The origin.
* @returns Whether the origin is allowed.
*/
function checkAllowedOrigin(matcher, origin) {
// If the matcher is a single wildcard or identical to the origin we can return true immediately.
if (matcher === '*' || matcher === origin) {
return true;
}
const regex = createOriginRegExp(matcher);
return regex.test(origin);
}
/**
* Check if the given origin is allowed by the given JSON-RPC origins object.
*
* @param origins - The JSON-RPC origins object.
* @param subjectType - The type of the origin.
* @param origin - The origin to check.
* @returns Whether the origin is allowed.
*/
function isOriginAllowed(origins, subjectType, origin) {
// The MetaMask client is always allowed.
if (origin === 'metamask') {
return true;
}
// If the origin is in the `allowedOrigins` list, it is allowed.
if (origins.allowedOrigins?.some((matcher) => checkAllowedOrigin(matcher, origin))) {
return true;
}
// If the origin is a website and `dapps` is true, it is allowed.
if (subjectType === permission_controller_1.SubjectType.Website && origins.dapps) {
return true;
}
// If the origin is a snap and `snaps` is true, it is allowed.
return Boolean(subjectType === permission_controller_1.SubjectType.Snap && origins.snaps);
}
exports.isOriginAllowed = isOriginAllowed;
/**
* Assert that the given value is a successful JSON-RPC response. If the value
* is not a success response, an error is thrown. If the value is an JSON-RPC
* error, the error message is included in the thrown error.
*
* @param value - The value to check.
* @throws If the value is not a JSON-RPC success response.
*/
function assertIsJsonRpcSuccess(value) {
if (!(0, utils_1.isJsonRpcSuccess)(value)) {
if ((0, utils_1.isJsonRpcFailure)(value)) {
throw new Error(`JSON-RPC request failed: ${value.error.message}`);
}
throw new Error('Invalid JSON-RPC response.');
}
}
exports.assertIsJsonRpcSuccess = assertIsJsonRpcSuccess;
//# sourceMappingURL=json-rpc.cjs.map