UNPKG

@metamask/snaps-rpc-methods

Version:
154 lines 7.07 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.getValidatedParams = exports.getImplementation = exports.notifyBuilder = exports.specificationBuilder = void 0; const permission_controller_1 = require("@metamask/permission-controller"); const rpc_errors_1 = require("@metamask/rpc-errors"); const snaps_sdk_1 = require("@metamask/snaps-sdk"); const snaps_utils_1 = require("@metamask/snaps-utils"); const superstruct_1 = require("@metamask/superstruct"); const utils_1 = require("@metamask/utils"); const methodName = 'snap_notify'; const NativeNotificationStruct = (0, superstruct_1.object)({ type: (0, snaps_sdk_1.enumValue)(snaps_sdk_1.NotificationType.Native), message: (0, superstruct_1.string)(), }); const InAppNotificationStruct = (0, superstruct_1.object)({ type: (0, snaps_sdk_1.enumValue)(snaps_sdk_1.NotificationType.InApp), message: (0, superstruct_1.string)(), }); const InAppNotificationWithDetailsStruct = (0, superstruct_1.object)({ type: (0, snaps_sdk_1.enumValue)(snaps_sdk_1.NotificationType.InApp), message: (0, superstruct_1.string)(), content: snaps_sdk_1.ComponentOrElementStruct, title: (0, superstruct_1.string)(), footerLink: (0, superstruct_1.optional)((0, superstruct_1.object)({ href: (0, superstruct_1.string)(), text: (0, superstruct_1.string)(), })), }); const NotificationParametersStruct = (0, snaps_sdk_1.union)([ InAppNotificationStruct, InAppNotificationWithDetailsStruct, NativeNotificationStruct, ]); /** * The specification builder for the `snap_notify` permission. * `snap_notify` allows snaps to send multiple types of notifications to its users. * * @param options - The specification builder options. * @param options.allowedCaveats - The optional allowed caveats for the permission. * @param options.methodHooks - The RPC method hooks needed by the method implementation. * @returns The specification for the `snap_notify` permission. */ const specificationBuilder = ({ allowedCaveats = null, methodHooks }) => { return { permissionType: permission_controller_1.PermissionType.RestrictedMethod, targetName: methodName, allowedCaveats, methodImplementation: getImplementation(methodHooks), subjectTypes: [permission_controller_1.SubjectType.Snap], }; }; exports.specificationBuilder = specificationBuilder; const methodHooks = { showNativeNotification: true, showInAppNotification: true, isOnPhishingList: true, maybeUpdatePhishingList: true, createInterface: true, getSnap: true, }; exports.notifyBuilder = Object.freeze({ targetName: methodName, specificationBuilder: exports.specificationBuilder, methodHooks, }); /** * Builds the method implementation for `snap_notify`. * * @param hooks - The RPC method hooks. * @param hooks.showNativeNotification - A function that shows a native browser notification. * @param hooks.showInAppNotification - A function that shows a notification in the MetaMask UI. * @param hooks.isOnPhishingList - A function that checks for links against the phishing list. * @param hooks.maybeUpdatePhishingList - A function that updates the phishing list if needed. * @param hooks.createInterface - A function that creates the interface in SnapInterfaceController. * @param hooks.getSnap - A function that checks if a snap is installed. * @returns The method implementation which returns `null` on success. * @throws If the params are invalid. */ function getImplementation({ showNativeNotification, showInAppNotification, isOnPhishingList, maybeUpdatePhishingList, createInterface, getSnap, }) { return async function implementation(args) { const { params, context: { origin }, } = args; await maybeUpdatePhishingList(); const validatedParams = getValidatedParams(params, isOnPhishingList, getSnap); if ((0, utils_1.hasProperty)(validatedParams, 'content')) { const id = await createInterface(origin, validatedParams.content, undefined, snaps_sdk_1.ContentType.Notification); validatedParams.content = id; } switch (validatedParams.type) { case snaps_sdk_1.NotificationType.Native: return await showNativeNotification(origin, validatedParams); case snaps_sdk_1.NotificationType.InApp: return await showInAppNotification(origin, validatedParams); default: throw rpc_errors_1.rpcErrors.invalidParams({ message: 'Must specify a valid notification "type".', }); } }; } exports.getImplementation = getImplementation; /** * Validates the notify method `params` and returns them cast to the correct * type. Throws if validation fails. * * @param params - The unvalidated params object from the method request. * @param isOnPhishingList - The function that checks for links against the phishing list. * @param getSnap - A function that checks if a snap is installed. * @returns The validated method parameter object. * @throws If the params are invalid. */ function getValidatedParams(params, isOnPhishingList, getSnap) { if (!(0, utils_1.isObject)(params)) { throw rpc_errors_1.rpcErrors.invalidParams({ message: 'Expected params to be a single object.', }); } const { type, message } = params; if (!type || typeof type !== 'string' || !Object.values(snaps_sdk_1.NotificationType).includes(type)) { throw rpc_errors_1.rpcErrors.invalidParams({ message: 'Must specify a valid notification "type".', }); } const isNotString = !message || typeof message !== 'string'; // Set to the max message length on a Mac notification for now. if (type === snaps_sdk_1.NotificationType.Native && (isNotString || message.length >= 50)) { throw rpc_errors_1.rpcErrors.invalidParams({ message: 'Must specify a non-empty string "message" less than 50 characters long.', }); } if (type === snaps_sdk_1.NotificationType.InApp && (isNotString || message.length >= 500)) { throw rpc_errors_1.rpcErrors.invalidParams({ message: 'Must specify a non-empty string "message" less than 500 characters long.', }); } try { const validatedParams = (0, snaps_utils_1.createUnion)(params, NotificationParametersStruct, 'type'); (0, snaps_utils_1.validateTextLinks)(validatedParams.message, isOnPhishingList, getSnap); if ((0, utils_1.hasProperty)(validatedParams, 'footerLink')) { (0, snaps_utils_1.validateLink)(validatedParams.footerLink.href, isOnPhishingList, getSnap); } return validatedParams; } catch (error) { throw rpc_errors_1.rpcErrors.invalidParams({ message: `Invalid params: ${(0, snaps_sdk_1.getErrorMessage)(error)}`, }); } } exports.getValidatedParams = getValidatedParams; //# sourceMappingURL=notify.cjs.map