@metamask/snaps-controllers 18.0.0 → 18.0.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +27 -1
- package/dist/interface/SnapInterfaceController.cjs.map +1 -1
- package/dist/interface/SnapInterfaceController.d.cts +8 -2
- package/dist/interface/SnapInterfaceController.d.cts.map +1 -1
- package/dist/interface/SnapInterfaceController.d.mts +8 -2
- package/dist/interface/SnapInterfaceController.d.mts.map +1 -1
- package/dist/interface/SnapInterfaceController.mjs.map +1 -1
- package/dist/services/AbstractExecutionService.cjs +8 -11
- package/dist/services/AbstractExecutionService.cjs.map +1 -1
- package/dist/services/AbstractExecutionService.d.cts +3 -2
- package/dist/services/AbstractExecutionService.d.cts.map +1 -1
- package/dist/services/AbstractExecutionService.d.mts +3 -2
- package/dist/services/AbstractExecutionService.d.mts.map +1 -1
- package/dist/services/AbstractExecutionService.mjs +9 -12
- package/dist/services/AbstractExecutionService.mjs.map +1 -1
- package/dist/snaps/SnapController.cjs +36 -8
- package/dist/snaps/SnapController.cjs.map +1 -1
- package/dist/snaps/SnapController.d.cts +4 -1
- package/dist/snaps/SnapController.d.cts.map +1 -1
- package/dist/snaps/SnapController.d.mts +4 -1
- package/dist/snaps/SnapController.d.mts.map +1 -1
- package/dist/snaps/SnapController.mjs +36 -8
- package/dist/snaps/SnapController.mjs.map +1 -1
- package/package.json +5 -6
|
@@ -1,7 +1,8 @@
|
|
|
1
|
-
import { JsonRpcEngine } from "@metamask/json-rpc-engine";
|
|
1
|
+
import { JsonRpcEngineV2 as JsonRpcEngine } from "@metamask/json-rpc-engine/v2";
|
|
2
2
|
import ObjectMultiplex from "@metamask/object-multiplex";
|
|
3
3
|
import type { BasePostMessageStream } from "@metamask/post-message-stream";
|
|
4
4
|
import type { SnapRpcHookArgs } from "@metamask/snaps-utils";
|
|
5
|
+
import type { JsonRpcRequest } from "@metamask/utils";
|
|
5
6
|
import type { Duplex } from "readable-stream";
|
|
6
7
|
import type { ExecutionService, ExecutionServiceMessenger, SnapExecutionData } from "./ExecutionService.mjs";
|
|
7
8
|
declare const controllerName = "ExecutionService";
|
|
@@ -23,7 +24,7 @@ export type JobStreams = {
|
|
|
23
24
|
export type Job<WorkerType> = {
|
|
24
25
|
id: string;
|
|
25
26
|
streams: JobStreams;
|
|
26
|
-
rpcEngine: JsonRpcEngine
|
|
27
|
+
rpcEngine: JsonRpcEngine<JsonRpcRequest>;
|
|
27
28
|
worker: WorkerType;
|
|
28
29
|
};
|
|
29
30
|
export type TerminateJobArgs<WorkerType> = Partial<Job<WorkerType>> & Pick<Job<WorkerType>, 'id'>;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"AbstractExecutionService.d.mts","sourceRoot":"","sources":["../../src/services/AbstractExecutionService.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"AbstractExecutionService.d.mts","sourceRoot":"","sources":["../../src/services/AbstractExecutionService.ts"],"names":[],"mappings":"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"}
|
|
@@ -4,11 +4,11 @@ function $importDefault(module) {
|
|
|
4
4
|
}
|
|
5
5
|
return module;
|
|
6
6
|
}
|
|
7
|
-
import {
|
|
7
|
+
import { asV2Middleware } from "@metamask/json-rpc-engine";
|
|
8
|
+
import { JsonRpcEngineV2 as JsonRpcEngine } from "@metamask/json-rpc-engine/v2";
|
|
8
9
|
import { createStreamMiddleware } from "@metamask/json-rpc-middleware-stream";
|
|
9
10
|
import $ObjectMultiplex from "@metamask/object-multiplex";
|
|
10
11
|
const ObjectMultiplex = $importDefault($ObjectMultiplex);
|
|
11
|
-
import { JsonRpcError } from "@metamask/rpc-errors";
|
|
12
12
|
import { SNAP_STREAM_NAMES, logError, logWarning } from "@metamask/snaps-utils";
|
|
13
13
|
import { Duration, assertIsJsonRpcRequest, hasProperty, inMilliseconds } from "@metamask/utils";
|
|
14
14
|
import { nanoid } from "nanoid";
|
|
@@ -100,14 +100,15 @@ export class AbstractExecutionService {
|
|
|
100
100
|
*/
|
|
101
101
|
async #initJob(snapId, timer) {
|
|
102
102
|
const { streams, worker } = await this.#initStreams(snapId, timer);
|
|
103
|
-
const rpcEngine = new JsonRpcEngine();
|
|
104
103
|
const jsonRpcConnection = createStreamMiddleware();
|
|
105
104
|
pipeline(jsonRpcConnection.stream, streams.command, jsonRpcConnection.stream, (error) => {
|
|
106
105
|
if (error && !error.message?.match('Premature close')) {
|
|
107
106
|
logError(`Command stream failure.`, error);
|
|
108
107
|
}
|
|
109
108
|
});
|
|
110
|
-
rpcEngine.
|
|
109
|
+
const rpcEngine = JsonRpcEngine.create({
|
|
110
|
+
middleware: [asV2Middleware(jsonRpcConnection.middleware)],
|
|
111
|
+
});
|
|
111
112
|
const envMetadata = {
|
|
112
113
|
id: snapId,
|
|
113
114
|
streams,
|
|
@@ -161,7 +162,9 @@ export class AbstractExecutionService {
|
|
|
161
162
|
}
|
|
162
163
|
};
|
|
163
164
|
commandStream.on('data', notificationHandler);
|
|
164
|
-
const rpcStream = mux
|
|
165
|
+
const rpcStream = mux
|
|
166
|
+
.createStream(SNAP_STREAM_NAMES.JSON_RPC)
|
|
167
|
+
.setMaxListeners(20);
|
|
165
168
|
rpcStream.on('data', (chunk) => {
|
|
166
169
|
if (chunk?.data && hasProperty(chunk?.data, 'id')) {
|
|
167
170
|
this.#messenger.publish('ExecutionService:outboundRequest', snapId);
|
|
@@ -260,13 +263,7 @@ export class AbstractExecutionService {
|
|
|
260
263
|
throw new Error(`"${snapId}" is not currently running.`);
|
|
261
264
|
}
|
|
262
265
|
log('Parent: Sending Command', message);
|
|
263
|
-
|
|
264
|
-
// We don't need full validation of the response here because we control it.
|
|
265
|
-
if (hasProperty(response, 'error')) {
|
|
266
|
-
const error = response.error;
|
|
267
|
-
throw new JsonRpcError(error.code, error.message, error.data);
|
|
268
|
-
}
|
|
269
|
-
return response.result;
|
|
266
|
+
return await job.rpcEngine.handle(message);
|
|
270
267
|
}
|
|
271
268
|
/**
|
|
272
269
|
* Handle RPC request.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"AbstractExecutionService.mjs","sourceRoot":"","sources":["../../src/services/AbstractExecutionService.ts"],"names":[],"mappings":"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","sourcesContent":["import { JsonRpcEngine } from '@metamask/json-rpc-engine';\nimport { createStreamMiddleware } from '@metamask/json-rpc-middleware-stream';\nimport ObjectMultiplex from '@metamask/object-multiplex';\nimport type { BasePostMessageStream } from '@metamask/post-message-stream';\nimport { JsonRpcError } from '@metamask/rpc-errors';\nimport type { SnapRpcHookArgs } from '@metamask/snaps-utils';\nimport { SNAP_STREAM_NAMES, logError, logWarning } from '@metamask/snaps-utils';\nimport type {\n Json,\n JsonRpcError as JsonRpcErrorType,\n JsonRpcNotification,\n JsonRpcRequest,\n} from '@metamask/utils';\nimport {\n Duration,\n assertIsJsonRpcRequest,\n hasProperty,\n inMilliseconds,\n} from '@metamask/utils';\nimport { nanoid } from 'nanoid';\nimport { pipeline } from 'readable-stream';\nimport type { Duplex } from 'readable-stream';\n\nimport type {\n ExecutionService,\n ExecutionServiceMessenger,\n SnapErrorJson,\n SnapExecutionData,\n} from './ExecutionService';\nimport { log } from '../logging';\nimport { Timer } from '../snaps/Timer';\nimport { hasTimedOut, withTimeout } from '../utils';\n\nconst controllerName = 'ExecutionService';\n\nexport type SetupSnapProvider = (snapId: string, stream: Duplex) => void;\n\nexport type ExecutionServiceArgs = {\n setupSnapProvider: SetupSnapProvider;\n messenger: ExecutionServiceMessenger;\n initTimeout?: number;\n pingTimeout?: number;\n terminationTimeout?: number;\n usePing?: boolean;\n};\n\nexport type JobStreams = {\n command: Duplex;\n rpc: Duplex;\n connection: BasePostMessageStream;\n mux: ObjectMultiplex;\n};\n\nexport type Job<WorkerType> = {\n id: string;\n streams: JobStreams;\n rpcEngine: JsonRpcEngine;\n worker: WorkerType;\n};\n\nexport type TerminateJobArgs<WorkerType> = Partial<Job<WorkerType>> &\n Pick<Job<WorkerType>, 'id'>;\n\n/** \n Statuses used for diagnostic purposes\n - created: The initial state, no initialization has started \n - initializing: Snap execution environment is initializing\n - initialized: Snap execution environment has initialized\n - executing: Snap source code is being executed\n - running: Snap executed and ready for RPC requests\n */\ntype ExecutionStatus =\n | 'created'\n | 'initializing'\n | 'initialized'\n | 'executing'\n | 'running';\n\nexport abstract class AbstractExecutionService<WorkerType>\n implements ExecutionService\n{\n name: typeof controllerName = controllerName;\n\n state = null;\n\n readonly #jobs: Map<string, Job<WorkerType>>;\n\n readonly #status: Map<string, ExecutionStatus>;\n\n readonly #setupSnapProvider: SetupSnapProvider;\n\n readonly #messenger: ExecutionServiceMessenger;\n\n readonly #initTimeout: number;\n\n readonly #pingTimeout: number;\n\n readonly #terminationTimeout: number;\n\n readonly #usePing: boolean;\n\n constructor({\n setupSnapProvider,\n messenger,\n initTimeout = inMilliseconds(60, Duration.Second),\n pingTimeout = inMilliseconds(10, Duration.Second),\n terminationTimeout = inMilliseconds(1, Duration.Second),\n usePing = true,\n }: ExecutionServiceArgs) {\n this.#jobs = new Map();\n this.#status = new Map();\n this.#setupSnapProvider = setupSnapProvider;\n this.#messenger = messenger;\n this.#initTimeout = initTimeout;\n this.#pingTimeout = pingTimeout;\n this.#terminationTimeout = terminationTimeout;\n this.#usePing = usePing;\n\n this.#registerMessageHandlers();\n }\n\n /**\n * Constructor helper for registering the controller's messaging system\n * actions.\n */\n #registerMessageHandlers(): void {\n this.#messenger.registerActionHandler(\n `${controllerName}:handleRpcRequest`,\n async (snapId: string, options: SnapRpcHookArgs) =>\n this.handleRpcRequest(snapId, options),\n );\n\n this.#messenger.registerActionHandler(\n `${controllerName}:executeSnap`,\n async (data: SnapExecutionData) => this.executeSnap(data),\n );\n\n this.#messenger.registerActionHandler(\n `${controllerName}:terminateSnap`,\n async (snapId: string) => this.terminateSnap(snapId),\n );\n\n this.#messenger.registerActionHandler(\n `${controllerName}:terminateAllSnaps`,\n async () => this.terminateAllSnaps(),\n );\n }\n\n /**\n * Performs additional necessary work during job termination. **MUST** be\n * implemented by concrete implementations. See\n * {@link AbstractExecutionService.terminate} for details.\n *\n * @param job - The object corresponding to the job to be terminated.\n */\n protected abstract terminateJob(\n job: TerminateJobArgs<WorkerType>,\n ): Promise<void>;\n\n /**\n * Terminates the Snap with the specified ID and deletes all its associated\n * data. Any subsequent messages targeting the Snap will fail with an error.\n * Throws an error if termination fails unexpectedly.\n *\n * @param snapId - The id of the Snap to be terminated.\n */\n public async terminateSnap(snapId: string): Promise<void> {\n const job = this.#jobs.get(snapId);\n if (!job) {\n return;\n }\n\n try {\n // Ping worker and tell it to run teardown, continue with termination if it takes too long\n const result = await withTimeout(\n this.#command(snapId, {\n jsonrpc: '2.0',\n method: 'terminate',\n id: nanoid(),\n }),\n this.#terminationTimeout,\n );\n\n if (result === hasTimedOut || result !== 'OK') {\n logWarning(`Snap \"${snapId}\" failed to terminate gracefully.`);\n }\n } catch {\n // Ignore\n }\n\n Object.values(job.streams).forEach((stream) => {\n try {\n if (!stream.destroyed) {\n stream.destroy();\n }\n } catch (error) {\n logError('Error while destroying stream', error);\n }\n });\n\n await this.terminateJob(job);\n\n this.#jobs.delete(snapId);\n this.#status.delete(snapId);\n log(`Snap \"${snapId}\" terminated.`);\n }\n\n /**\n * Initiates a job for a Snap.\n *\n * @param snapId - The ID of the Snap to initiate a job for.\n * @param timer - The timer to use for timeouts.\n * @returns Information regarding the created job.\n * @throws If the execution service returns an error or execution times out.\n */\n async #initJob(snapId: string, timer: Timer): Promise<Job<WorkerType>> {\n const { streams, worker } = await this.#initStreams(snapId, timer);\n const rpcEngine = new JsonRpcEngine();\n\n const jsonRpcConnection = createStreamMiddleware();\n\n pipeline(\n jsonRpcConnection.stream,\n streams.command,\n jsonRpcConnection.stream,\n (error) => {\n if (error && !error.message?.match('Premature close')) {\n logError(`Command stream failure.`, error);\n }\n },\n );\n\n rpcEngine.push(jsonRpcConnection.middleware);\n\n const envMetadata = {\n id: snapId,\n streams,\n rpcEngine,\n worker,\n };\n this.#jobs.set(snapId, envMetadata);\n\n return envMetadata;\n }\n\n /**\n * Sets up the streams for an initiated job.\n *\n * @param snapId - The Snap ID.\n * @param timer - The timer to use for timeouts.\n * @returns The streams to communicate with the worker and the worker itself.\n * @throws If the execution service returns an error or execution times out.\n */\n async #initStreams(\n snapId: string,\n timer: Timer,\n ): Promise<{ streams: JobStreams; worker: WorkerType }> {\n const result = await withTimeout(this.initEnvStream(snapId), timer);\n\n if (result === hasTimedOut) {\n // For certain environments, such as the iframe we may have already created the worker and wish to terminate it.\n await this.terminateJob({ id: snapId });\n\n const status = this.#status.get(snapId);\n if (status === 'created') {\n // Currently this error can only be thrown by OffscreenExecutionService.\n throw new Error(\n `The executor for \"${snapId}\" couldn't start initialization. The offscreen document may not exist.`,\n );\n }\n throw new Error(\n `The executor for \"${snapId}\" failed to initialize. The iframe/webview/worker failed to load.`,\n );\n }\n\n const { worker, stream: envStream } = result;\n const mux = setupMultiplex(envStream, `Snap: \"${snapId}\"`);\n const commandStream = mux.createStream(SNAP_STREAM_NAMES.COMMAND);\n\n // Handle out-of-band errors, i.e. errors thrown from the Snap outside of the req/res cycle.\n // Also keep track of outbound request/responses\n const notificationHandler = (\n message:\n | JsonRpcRequest\n | JsonRpcNotification<Json[] | Record<string, Json>>,\n ) => {\n if (hasProperty(message, 'id')) {\n return;\n }\n\n if (message.method === 'OutboundRequest') {\n this.#messenger.publish('ExecutionService:outboundRequest', snapId);\n } else if (message.method === 'OutboundResponse') {\n this.#messenger.publish('ExecutionService:outboundResponse', snapId);\n } else if (message.method === 'UnhandledError') {\n this.#messenger.publish(\n 'ExecutionService:unhandledError',\n snapId,\n (message.params as { error: SnapErrorJson }).error,\n );\n commandStream.removeListener('data', notificationHandler);\n } else {\n logError(\n new Error(\n `Received unexpected command stream notification \"${message.method}\".`,\n ),\n );\n }\n };\n\n commandStream.on('data', notificationHandler);\n\n const rpcStream = mux.createStream(SNAP_STREAM_NAMES.JSON_RPC);\n\n rpcStream.on('data', (chunk) => {\n if (chunk?.data && hasProperty(chunk?.data, 'id')) {\n this.#messenger.publish('ExecutionService:outboundRequest', snapId);\n }\n });\n\n const originalWrite = rpcStream.write.bind(rpcStream);\n\n // @ts-expect-error Hack to inspect the messages being written to the stream.\n rpcStream.write = (chunk, encoding, callback) => {\n // Ignore chain switching notifications as it doesn't matter for the SnapProvider.\n if (chunk?.data?.method === 'metamask_chainChanged') {\n return true;\n }\n\n if (chunk?.data && hasProperty(chunk?.data, 'id')) {\n this.#messenger.publish('ExecutionService:outboundResponse', snapId);\n }\n\n return originalWrite(chunk, encoding, callback);\n };\n\n return {\n streams: {\n command: commandStream,\n rpc: rpcStream,\n connection: envStream,\n mux,\n },\n worker,\n };\n }\n\n /**\n * Abstract function implemented by implementing class that spins up a new worker for a job.\n *\n * Depending on the execution environment, this may run forever if the Snap fails to start up properly, therefore any call to this function should be wrapped in a timeout.\n */\n protected abstract initEnvStream(snapId: string): Promise<{\n worker: WorkerType;\n stream: BasePostMessageStream;\n }>;\n\n /**\n * Set the execution status of the Snap.\n *\n * @param snapId - The Snap ID.\n * @param status - The current execution status.\n */\n protected setSnapStatus(snapId: string, status: ExecutionStatus) {\n this.#status.set(snapId, status);\n }\n\n async terminateAllSnaps() {\n await Promise.all(\n [...this.#jobs.keys()].map(async (snapId) => this.terminateSnap(snapId)),\n );\n }\n\n /**\n * Initializes and executes a Snap, setting up the communication channels to the Snap etc.\n *\n * @param snapData - Data needed for Snap execution.\n * @param snapData.snapId - The ID of the Snap to execute.\n * @param snapData.sourceCode - The source code of the Snap to execute.\n * @param snapData.endowments - The endowments available to the executing Snap.\n * @returns A string `OK` if execution succeeded.\n * @throws If the execution service returns an error or execution times out.\n */\n async executeSnap({\n snapId,\n sourceCode,\n endowments,\n }: SnapExecutionData): Promise<string> {\n if (this.#jobs.has(snapId)) {\n throw new Error(`\"${snapId}\" is already running.`);\n }\n\n this.setSnapStatus(snapId, 'created');\n\n const timer = new Timer(this.#initTimeout);\n\n // This may resolve even if the environment has failed to start up fully\n const job = await this.#initJob(snapId, timer);\n\n // Certain environments use ping as part of their initialization and thus can skip it here\n if (this.#usePing) {\n // Ping the worker to ensure that it started up\n const pingResult = await withTimeout(\n this.#command(job.id, {\n jsonrpc: '2.0',\n method: 'ping',\n id: nanoid(),\n }),\n this.#pingTimeout,\n );\n\n if (pingResult === hasTimedOut) {\n throw new Error(\n `The executor for \"${snapId}\" was unreachable. The executor did not respond in time.`,\n );\n }\n }\n\n const rpcStream = job.streams.rpc;\n\n this.#setupSnapProvider(snapId, rpcStream);\n\n // Use the remaining time as the timer, but ensure that the\n // Snap gets at least half the init timeout.\n const remainingTime = Math.max(timer.remaining, this.#initTimeout / 2);\n\n this.setSnapStatus(snapId, 'initialized');\n\n const request = {\n jsonrpc: '2.0',\n method: 'executeSnap',\n params: { snapId, sourceCode, endowments },\n id: nanoid(),\n };\n\n assertIsJsonRpcRequest(request);\n\n this.setSnapStatus(snapId, 'executing');\n\n const result = await withTimeout(\n this.#command(job.id, request),\n remainingTime,\n );\n\n if (result === hasTimedOut) {\n throw new Error(`${snapId} failed to start.`);\n }\n\n if (result === 'OK') {\n this.setSnapStatus(snapId, 'running');\n }\n\n return result as string;\n }\n\n async #command(\n snapId: string,\n message: JsonRpcRequest,\n ): Promise<Json | undefined> {\n const job = this.#jobs.get(snapId);\n if (!job) {\n throw new Error(`\"${snapId}\" is not currently running.`);\n }\n\n log('Parent: Sending Command', message);\n const response = await job.rpcEngine.handle(message);\n\n // We don't need full validation of the response here because we control it.\n if (hasProperty(response, 'error')) {\n const error = response.error as JsonRpcErrorType;\n throw new JsonRpcError(error.code, error.message, error.data);\n }\n\n return response.result;\n }\n\n /**\n * Handle RPC request.\n *\n * @param snapId - The ID of the recipient Snap.\n * @param options - Bag of options to pass to the RPC handler.\n * @returns Promise that can handle the request.\n */\n public async handleRpcRequest(\n snapId: string,\n options: SnapRpcHookArgs,\n ): Promise<unknown> {\n const { handler, request, origin } = options;\n\n return await this.#command(snapId, {\n id: nanoid(),\n jsonrpc: '2.0',\n method: 'snapRpc',\n params: {\n snapId,\n origin,\n handler,\n request: request as JsonRpcRequest,\n },\n });\n }\n}\n\n/**\n * Sets up stream multiplexing for the given stream.\n *\n * @param connectionStream - The stream to mux.\n * @param streamName - The name of the stream, for identification in errors.\n * @returns The multiplexed stream.\n */\nexport function setupMultiplex(\n connectionStream: Duplex,\n streamName: string,\n): ObjectMultiplex {\n const mux = new ObjectMultiplex();\n pipeline(connectionStream, mux, connectionStream, (error) => {\n if (error && !error.message?.match('Premature close')) {\n logError(`\"${streamName}\" stream failure.`, error);\n }\n });\n return mux;\n}\n"]}
|
|
1
|
+
{"version":3,"file":"AbstractExecutionService.mjs","sourceRoot":"","sources":["../../src/services/AbstractExecutionService.ts"],"names":[],"mappings":"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","sourcesContent":["import { asV2Middleware } from '@metamask/json-rpc-engine';\nimport { JsonRpcEngineV2 as JsonRpcEngine } from '@metamask/json-rpc-engine/v2';\nimport { createStreamMiddleware } from '@metamask/json-rpc-middleware-stream';\nimport ObjectMultiplex from '@metamask/object-multiplex';\nimport type { BasePostMessageStream } from '@metamask/post-message-stream';\nimport type { SnapRpcHookArgs } from '@metamask/snaps-utils';\nimport { SNAP_STREAM_NAMES, logError, logWarning } from '@metamask/snaps-utils';\nimport type {\n Json,\n JsonRpcNotification,\n JsonRpcRequest,\n} from '@metamask/utils';\nimport {\n Duration,\n assertIsJsonRpcRequest,\n hasProperty,\n inMilliseconds,\n} from '@metamask/utils';\nimport { nanoid } from 'nanoid';\nimport { pipeline } from 'readable-stream';\nimport type { Duplex } from 'readable-stream';\n\nimport type {\n ExecutionService,\n ExecutionServiceMessenger,\n SnapErrorJson,\n SnapExecutionData,\n} from './ExecutionService';\nimport { log } from '../logging';\nimport { Timer } from '../snaps/Timer';\nimport { hasTimedOut, withTimeout } from '../utils';\n\nconst controllerName = 'ExecutionService';\n\nexport type SetupSnapProvider = (snapId: string, stream: Duplex) => void;\n\nexport type ExecutionServiceArgs = {\n setupSnapProvider: SetupSnapProvider;\n messenger: ExecutionServiceMessenger;\n initTimeout?: number;\n pingTimeout?: number;\n terminationTimeout?: number;\n usePing?: boolean;\n};\n\nexport type JobStreams = {\n command: Duplex;\n rpc: Duplex;\n connection: BasePostMessageStream;\n mux: ObjectMultiplex;\n};\n\nexport type Job<WorkerType> = {\n id: string;\n streams: JobStreams;\n rpcEngine: JsonRpcEngine<JsonRpcRequest>;\n worker: WorkerType;\n};\n\nexport type TerminateJobArgs<WorkerType> = Partial<Job<WorkerType>> &\n Pick<Job<WorkerType>, 'id'>;\n\n/** \n Statuses used for diagnostic purposes\n - created: The initial state, no initialization has started \n - initializing: Snap execution environment is initializing\n - initialized: Snap execution environment has initialized\n - executing: Snap source code is being executed\n - running: Snap executed and ready for RPC requests\n */\ntype ExecutionStatus =\n | 'created'\n | 'initializing'\n | 'initialized'\n | 'executing'\n | 'running';\n\nexport abstract class AbstractExecutionService<WorkerType>\n implements ExecutionService\n{\n name: typeof controllerName = controllerName;\n\n state = null;\n\n readonly #jobs: Map<string, Job<WorkerType>>;\n\n readonly #status: Map<string, ExecutionStatus>;\n\n readonly #setupSnapProvider: SetupSnapProvider;\n\n readonly #messenger: ExecutionServiceMessenger;\n\n readonly #initTimeout: number;\n\n readonly #pingTimeout: number;\n\n readonly #terminationTimeout: number;\n\n readonly #usePing: boolean;\n\n constructor({\n setupSnapProvider,\n messenger,\n initTimeout = inMilliseconds(60, Duration.Second),\n pingTimeout = inMilliseconds(10, Duration.Second),\n terminationTimeout = inMilliseconds(1, Duration.Second),\n usePing = true,\n }: ExecutionServiceArgs) {\n this.#jobs = new Map();\n this.#status = new Map();\n this.#setupSnapProvider = setupSnapProvider;\n this.#messenger = messenger;\n this.#initTimeout = initTimeout;\n this.#pingTimeout = pingTimeout;\n this.#terminationTimeout = terminationTimeout;\n this.#usePing = usePing;\n\n this.#registerMessageHandlers();\n }\n\n /**\n * Constructor helper for registering the controller's messaging system\n * actions.\n */\n #registerMessageHandlers(): void {\n this.#messenger.registerActionHandler(\n `${controllerName}:handleRpcRequest`,\n async (snapId: string, options: SnapRpcHookArgs) =>\n this.handleRpcRequest(snapId, options),\n );\n\n this.#messenger.registerActionHandler(\n `${controllerName}:executeSnap`,\n async (data: SnapExecutionData) => this.executeSnap(data),\n );\n\n this.#messenger.registerActionHandler(\n `${controllerName}:terminateSnap`,\n async (snapId: string) => this.terminateSnap(snapId),\n );\n\n this.#messenger.registerActionHandler(\n `${controllerName}:terminateAllSnaps`,\n async () => this.terminateAllSnaps(),\n );\n }\n\n /**\n * Performs additional necessary work during job termination. **MUST** be\n * implemented by concrete implementations. See\n * {@link AbstractExecutionService.terminate} for details.\n *\n * @param job - The object corresponding to the job to be terminated.\n */\n protected abstract terminateJob(\n job: TerminateJobArgs<WorkerType>,\n ): Promise<void>;\n\n /**\n * Terminates the Snap with the specified ID and deletes all its associated\n * data. Any subsequent messages targeting the Snap will fail with an error.\n * Throws an error if termination fails unexpectedly.\n *\n * @param snapId - The id of the Snap to be terminated.\n */\n public async terminateSnap(snapId: string): Promise<void> {\n const job = this.#jobs.get(snapId);\n if (!job) {\n return;\n }\n\n try {\n // Ping worker and tell it to run teardown, continue with termination if it takes too long\n const result = await withTimeout(\n this.#command(snapId, {\n jsonrpc: '2.0',\n method: 'terminate',\n id: nanoid(),\n }),\n this.#terminationTimeout,\n );\n\n if (result === hasTimedOut || result !== 'OK') {\n logWarning(`Snap \"${snapId}\" failed to terminate gracefully.`);\n }\n } catch {\n // Ignore\n }\n\n Object.values(job.streams).forEach((stream) => {\n try {\n if (!stream.destroyed) {\n stream.destroy();\n }\n } catch (error) {\n logError('Error while destroying stream', error);\n }\n });\n\n await this.terminateJob(job);\n\n this.#jobs.delete(snapId);\n this.#status.delete(snapId);\n log(`Snap \"${snapId}\" terminated.`);\n }\n\n /**\n * Initiates a job for a Snap.\n *\n * @param snapId - The ID of the Snap to initiate a job for.\n * @param timer - The timer to use for timeouts.\n * @returns Information regarding the created job.\n * @throws If the execution service returns an error or execution times out.\n */\n async #initJob(snapId: string, timer: Timer): Promise<Job<WorkerType>> {\n const { streams, worker } = await this.#initStreams(snapId, timer);\n\n const jsonRpcConnection = createStreamMiddleware();\n\n pipeline(\n jsonRpcConnection.stream,\n streams.command,\n jsonRpcConnection.stream,\n (error) => {\n if (error && !error.message?.match('Premature close')) {\n logError(`Command stream failure.`, error);\n }\n },\n );\n\n const rpcEngine = JsonRpcEngine.create({\n middleware: [asV2Middleware(jsonRpcConnection.middleware)],\n });\n\n const envMetadata = {\n id: snapId,\n streams,\n rpcEngine,\n worker,\n };\n this.#jobs.set(snapId, envMetadata);\n\n return envMetadata;\n }\n\n /**\n * Sets up the streams for an initiated job.\n *\n * @param snapId - The Snap ID.\n * @param timer - The timer to use for timeouts.\n * @returns The streams to communicate with the worker and the worker itself.\n * @throws If the execution service returns an error or execution times out.\n */\n async #initStreams(\n snapId: string,\n timer: Timer,\n ): Promise<{ streams: JobStreams; worker: WorkerType }> {\n const result = await withTimeout(this.initEnvStream(snapId), timer);\n\n if (result === hasTimedOut) {\n // For certain environments, such as the iframe we may have already created the worker and wish to terminate it.\n await this.terminateJob({ id: snapId });\n\n const status = this.#status.get(snapId);\n if (status === 'created') {\n // Currently this error can only be thrown by OffscreenExecutionService.\n throw new Error(\n `The executor for \"${snapId}\" couldn't start initialization. The offscreen document may not exist.`,\n );\n }\n throw new Error(\n `The executor for \"${snapId}\" failed to initialize. The iframe/webview/worker failed to load.`,\n );\n }\n\n const { worker, stream: envStream } = result;\n const mux = setupMultiplex(envStream, `Snap: \"${snapId}\"`);\n const commandStream = mux.createStream(SNAP_STREAM_NAMES.COMMAND);\n\n // Handle out-of-band errors, i.e. errors thrown from the Snap outside of the req/res cycle.\n // Also keep track of outbound request/responses\n const notificationHandler = (\n message:\n | JsonRpcRequest\n | JsonRpcNotification<Json[] | Record<string, Json>>,\n ) => {\n if (hasProperty(message, 'id')) {\n return;\n }\n\n if (message.method === 'OutboundRequest') {\n this.#messenger.publish('ExecutionService:outboundRequest', snapId);\n } else if (message.method === 'OutboundResponse') {\n this.#messenger.publish('ExecutionService:outboundResponse', snapId);\n } else if (message.method === 'UnhandledError') {\n this.#messenger.publish(\n 'ExecutionService:unhandledError',\n snapId,\n (message.params as { error: SnapErrorJson }).error,\n );\n commandStream.removeListener('data', notificationHandler);\n } else {\n logError(\n new Error(\n `Received unexpected command stream notification \"${message.method}\".`,\n ),\n );\n }\n };\n\n commandStream.on('data', notificationHandler);\n\n const rpcStream = mux\n .createStream(SNAP_STREAM_NAMES.JSON_RPC)\n .setMaxListeners(20);\n\n rpcStream.on('data', (chunk) => {\n if (chunk?.data && hasProperty(chunk?.data, 'id')) {\n this.#messenger.publish('ExecutionService:outboundRequest', snapId);\n }\n });\n\n const originalWrite = rpcStream.write.bind(rpcStream);\n\n // @ts-expect-error Hack to inspect the messages being written to the stream.\n rpcStream.write = (chunk, encoding, callback) => {\n // Ignore chain switching notifications as it doesn't matter for the SnapProvider.\n if (chunk?.data?.method === 'metamask_chainChanged') {\n return true;\n }\n\n if (chunk?.data && hasProperty(chunk?.data, 'id')) {\n this.#messenger.publish('ExecutionService:outboundResponse', snapId);\n }\n\n return originalWrite(chunk, encoding, callback);\n };\n\n return {\n streams: {\n command: commandStream,\n rpc: rpcStream,\n connection: envStream,\n mux,\n },\n worker,\n };\n }\n\n /**\n * Abstract function implemented by implementing class that spins up a new worker for a job.\n *\n * Depending on the execution environment, this may run forever if the Snap fails to start up properly, therefore any call to this function should be wrapped in a timeout.\n */\n protected abstract initEnvStream(snapId: string): Promise<{\n worker: WorkerType;\n stream: BasePostMessageStream;\n }>;\n\n /**\n * Set the execution status of the Snap.\n *\n * @param snapId - The Snap ID.\n * @param status - The current execution status.\n */\n protected setSnapStatus(snapId: string, status: ExecutionStatus) {\n this.#status.set(snapId, status);\n }\n\n async terminateAllSnaps() {\n await Promise.all(\n [...this.#jobs.keys()].map(async (snapId) => this.terminateSnap(snapId)),\n );\n }\n\n /**\n * Initializes and executes a Snap, setting up the communication channels to the Snap etc.\n *\n * @param snapData - Data needed for Snap execution.\n * @param snapData.snapId - The ID of the Snap to execute.\n * @param snapData.sourceCode - The source code of the Snap to execute.\n * @param snapData.endowments - The endowments available to the executing Snap.\n * @returns A string `OK` if execution succeeded.\n * @throws If the execution service returns an error or execution times out.\n */\n async executeSnap({\n snapId,\n sourceCode,\n endowments,\n }: SnapExecutionData): Promise<string> {\n if (this.#jobs.has(snapId)) {\n throw new Error(`\"${snapId}\" is already running.`);\n }\n\n this.setSnapStatus(snapId, 'created');\n\n const timer = new Timer(this.#initTimeout);\n\n // This may resolve even if the environment has failed to start up fully\n const job = await this.#initJob(snapId, timer);\n\n // Certain environments use ping as part of their initialization and thus can skip it here\n if (this.#usePing) {\n // Ping the worker to ensure that it started up\n const pingResult = await withTimeout(\n this.#command(job.id, {\n jsonrpc: '2.0',\n method: 'ping',\n id: nanoid(),\n }),\n this.#pingTimeout,\n );\n\n if (pingResult === hasTimedOut) {\n throw new Error(\n `The executor for \"${snapId}\" was unreachable. The executor did not respond in time.`,\n );\n }\n }\n\n const rpcStream = job.streams.rpc;\n\n this.#setupSnapProvider(snapId, rpcStream);\n\n // Use the remaining time as the timer, but ensure that the\n // Snap gets at least half the init timeout.\n const remainingTime = Math.max(timer.remaining, this.#initTimeout / 2);\n\n this.setSnapStatus(snapId, 'initialized');\n\n const request = {\n jsonrpc: '2.0',\n method: 'executeSnap',\n params: { snapId, sourceCode, endowments },\n id: nanoid(),\n };\n\n assertIsJsonRpcRequest(request);\n\n this.setSnapStatus(snapId, 'executing');\n\n const result = await withTimeout(\n this.#command(job.id, request),\n remainingTime,\n );\n\n if (result === hasTimedOut) {\n throw new Error(`${snapId} failed to start.`);\n }\n\n if (result === 'OK') {\n this.setSnapStatus(snapId, 'running');\n }\n\n return result as string;\n }\n\n async #command(\n snapId: string,\n message: JsonRpcRequest,\n ): Promise<Json | undefined> {\n const job = this.#jobs.get(snapId);\n if (!job) {\n throw new Error(`\"${snapId}\" is not currently running.`);\n }\n\n log('Parent: Sending Command', message);\n return await job.rpcEngine.handle(message);\n }\n\n /**\n * Handle RPC request.\n *\n * @param snapId - The ID of the recipient Snap.\n * @param options - Bag of options to pass to the RPC handler.\n * @returns Promise that can handle the request.\n */\n public async handleRpcRequest(\n snapId: string,\n options: SnapRpcHookArgs,\n ): Promise<unknown> {\n const { handler, request, origin } = options;\n\n return await this.#command(snapId, {\n id: nanoid(),\n jsonrpc: '2.0',\n method: 'snapRpc',\n params: {\n snapId,\n origin,\n handler,\n request: request as JsonRpcRequest,\n },\n });\n }\n}\n\n/**\n * Sets up stream multiplexing for the given stream.\n *\n * @param connectionStream - The stream to mux.\n * @param streamName - The name of the stream, for identification in errors.\n * @returns The multiplexed stream.\n */\nexport function setupMultiplex(\n connectionStream: Duplex,\n streamName: string,\n): ObjectMultiplex {\n const mux = new ObjectMultiplex();\n pipeline(connectionStream, mux, connectionStream, (error) => {\n if (error && !error.message?.match('Premature close')) {\n logError(`\"${streamName}\" stream failure.`, error);\n }\n });\n return mux;\n}\n"]}
|
|
@@ -309,15 +309,22 @@ class SnapController extends base_controller_1.BaseController {
|
|
|
309
309
|
*
|
|
310
310
|
* Currently this method sets up the controller and calls the `onStart` lifecycle hook for all
|
|
311
311
|
* runnable Snaps.
|
|
312
|
+
*
|
|
313
|
+
* @param waitForPlatform - Whether to wait for the platform to be ready before returning.
|
|
312
314
|
*/
|
|
313
|
-
async init() {
|
|
315
|
+
async init(waitForPlatform = true) {
|
|
314
316
|
try {
|
|
315
317
|
if (this.#preinstalledSnaps) {
|
|
316
318
|
await this.#handlePreinstalledSnaps(this.#preinstalledSnaps);
|
|
317
319
|
}
|
|
318
320
|
this.#controllerSetup.resolve();
|
|
319
321
|
// Populate the `isReady` state.
|
|
320
|
-
|
|
322
|
+
if (waitForPlatform) {
|
|
323
|
+
await this.#ensureCanUsePlatform();
|
|
324
|
+
}
|
|
325
|
+
else {
|
|
326
|
+
this.#ensureCanUsePlatform().catch(snaps_utils_1.logError);
|
|
327
|
+
}
|
|
321
328
|
this.#callLifecycleHooks(constants_1.METAMASK_ORIGIN, snaps_utils_1.HandlerType.OnStart);
|
|
322
329
|
}
|
|
323
330
|
catch (error) {
|
|
@@ -330,9 +337,16 @@ class SnapController extends base_controller_1.BaseController {
|
|
|
330
337
|
const existingSnap = this.get(snapId);
|
|
331
338
|
const isAlreadyInstalled = existingSnap !== undefined;
|
|
332
339
|
const isUpdate = isAlreadyInstalled && (0, utils_1.gtVersion)(manifest.version, existingSnap.version);
|
|
340
|
+
const isPreinstalled = existingSnap?.preinstalled === true;
|
|
341
|
+
const isMissingSource = isAlreadyInstalled &&
|
|
342
|
+
isPreinstalled &&
|
|
343
|
+
!(await this.#hasSourceCode(snapId));
|
|
333
344
|
// Disallow downgrades and overwriting non preinstalled snaps
|
|
345
|
+
// As a mitigation for state corruption on mobile, if the source code is missing
|
|
346
|
+
// we allow overwriting and potentially downgrading the current version of the preinstalled Snap.
|
|
334
347
|
if (isAlreadyInstalled &&
|
|
335
|
-
|
|
348
|
+
!isMissingSource &&
|
|
349
|
+
(!isUpdate || !isPreinstalled)) {
|
|
336
350
|
continue;
|
|
337
351
|
}
|
|
338
352
|
const manifestFile = new snaps_utils_1.VirtualFile({
|
|
@@ -386,9 +400,13 @@ class SnapController extends base_controller_1.BaseController {
|
|
|
386
400
|
if (isUpdate) {
|
|
387
401
|
this.messenger.publish('SnapController:snapUpdated', this.getTruncatedExpect(snapId), existingSnap.version, constants_1.METAMASK_ORIGIN, true);
|
|
388
402
|
}
|
|
389
|
-
else {
|
|
403
|
+
else if (!isMissingSource) {
|
|
390
404
|
this.messenger.publish('SnapController:snapInstalled', this.getTruncatedExpect(snapId), constants_1.METAMASK_ORIGIN, true);
|
|
391
405
|
}
|
|
406
|
+
if (isMissingSource) {
|
|
407
|
+
(0, snaps_utils_1.logWarning)(`The source code for "${snapId}" was missing and has been automatically restored. If you see this message, please file a bug report.`);
|
|
408
|
+
this.messenger.captureException?.(new Error(`The source code for "${snapId}" was missing and has been automatically restored. This could indicate persistence issues.`));
|
|
409
|
+
}
|
|
392
410
|
}
|
|
393
411
|
// Ensure all preinstalled Snaps have their expected permissions.
|
|
394
412
|
for (const snap of Object.values(this.state.snaps).filter(({ preinstalled }) => preinstalled)) {
|
|
@@ -1073,6 +1091,7 @@ class SnapController extends base_controller_1.BaseController {
|
|
|
1073
1091
|
/**
|
|
1074
1092
|
* Completely clear the controller's state: delete all associated data,
|
|
1075
1093
|
* handlers, event listeners, and permissions; tear down all snap providers.
|
|
1094
|
+
* Also re-initializes the controller after clearing the state.
|
|
1076
1095
|
*/
|
|
1077
1096
|
async clearState() {
|
|
1078
1097
|
const snapIds = Object.keys(this.state.snaps);
|
|
@@ -1087,10 +1106,9 @@ class SnapController extends base_controller_1.BaseController {
|
|
|
1087
1106
|
this.#snapsRuntimeData.clear();
|
|
1088
1107
|
this.#rollbackSnapshots.clear();
|
|
1089
1108
|
await this.#clearStorageService();
|
|
1090
|
-
|
|
1091
|
-
|
|
1092
|
-
|
|
1093
|
-
}
|
|
1109
|
+
this.#controllerSetup = (0, utils_1.createDeferredPromise)();
|
|
1110
|
+
// Re-initialize the controller after clearing the state, re-installing preinstalled Snaps etc.
|
|
1111
|
+
await this.init(false);
|
|
1094
1112
|
}
|
|
1095
1113
|
/**
|
|
1096
1114
|
* Removes the given snap from state, and clears all associated handlers
|
|
@@ -2565,6 +2583,16 @@ class SnapController extends base_controller_1.BaseController {
|
|
|
2565
2583
|
runtime.state = undefined;
|
|
2566
2584
|
}
|
|
2567
2585
|
}
|
|
2586
|
+
/**
|
|
2587
|
+
* Check whether a Snap has valid source code in storage.
|
|
2588
|
+
*
|
|
2589
|
+
* @param snapId - The Snap ID.
|
|
2590
|
+
* @returns True if the source code is valid, otherwise false.
|
|
2591
|
+
*/
|
|
2592
|
+
async #hasSourceCode(snapId) {
|
|
2593
|
+
const sourceCode = await this.#getSourceCode(snapId).catch(() => null);
|
|
2594
|
+
return typeof sourceCode === 'string';
|
|
2595
|
+
}
|
|
2568
2596
|
/**
|
|
2569
2597
|
* Retrieve the source code for a Snap from storage.
|
|
2570
2598
|
*
|