@metamask/snaps-controllers 4.1.0 → 5.0.0

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.
Files changed (141) hide show
  1. package/CHANGELOG.md +22 -1
  2. package/dist/cjs/cronjob/CronjobController.js +3 -3
  3. package/dist/cjs/cronjob/CronjobController.js.map +1 -1
  4. package/dist/cjs/index.js +1 -0
  5. package/dist/cjs/index.js.map +1 -1
  6. package/dist/cjs/interface/SnapInterfaceController.js +166 -0
  7. package/dist/cjs/interface/SnapInterfaceController.js.map +1 -0
  8. package/dist/cjs/interface/index.js +20 -0
  9. package/dist/cjs/interface/index.js.map +1 -0
  10. package/dist/cjs/interface/utils.js +59 -0
  11. package/dist/cjs/interface/utils.js.map +1 -0
  12. package/dist/cjs/services/browser.js +1 -0
  13. package/dist/cjs/services/browser.js.map +1 -1
  14. package/dist/cjs/services/index.js +1 -0
  15. package/dist/cjs/services/index.js.map +1 -1
  16. package/dist/cjs/services/webview/WebViewExecutionService.js +99 -0
  17. package/dist/cjs/services/webview/WebViewExecutionService.js.map +1 -0
  18. package/dist/cjs/services/webview/WebViewMessageStream.js +127 -0
  19. package/dist/cjs/services/webview/WebViewMessageStream.js.map +1 -0
  20. package/dist/cjs/services/webview/index.js +20 -0
  21. package/dist/cjs/services/webview/index.js.map +1 -0
  22. package/dist/cjs/snaps/SnapController.js +111 -51
  23. package/dist/cjs/snaps/SnapController.js.map +1 -1
  24. package/dist/cjs/snaps/constants.js +25 -0
  25. package/dist/cjs/snaps/constants.js.map +1 -0
  26. package/dist/cjs/snaps/index.js +0 -2
  27. package/dist/cjs/snaps/index.js.map +1 -1
  28. package/dist/cjs/snaps/location/npm.js +13 -2
  29. package/dist/cjs/snaps/location/npm.js.map +1 -1
  30. package/dist/esm/cronjob/CronjobController.js +2 -2
  31. package/dist/esm/cronjob/CronjobController.js.map +1 -1
  32. package/dist/esm/index.js +1 -0
  33. package/dist/esm/index.js.map +1 -1
  34. package/dist/esm/interface/SnapInterfaceController.js +158 -0
  35. package/dist/esm/interface/SnapInterfaceController.js.map +1 -0
  36. package/dist/esm/interface/index.js +3 -0
  37. package/dist/esm/interface/index.js.map +1 -0
  38. package/dist/esm/interface/utils.js +62 -0
  39. package/dist/esm/interface/utils.js.map +1 -0
  40. package/dist/esm/services/browser.js +1 -0
  41. package/dist/esm/services/browser.js.map +1 -1
  42. package/dist/esm/services/index.js +1 -0
  43. package/dist/esm/services/index.js.map +1 -1
  44. package/dist/esm/services/webview/WebViewExecutionService.js +89 -0
  45. package/dist/esm/services/webview/WebViewExecutionService.js.map +1 -0
  46. package/dist/esm/services/webview/WebViewMessageStream.js +119 -0
  47. package/dist/esm/services/webview/WebViewMessageStream.js.map +1 -0
  48. package/dist/esm/services/webview/index.js +3 -0
  49. package/dist/esm/services/webview/index.js.map +1 -0
  50. package/dist/esm/snaps/SnapController.js +105 -45
  51. package/dist/esm/snaps/SnapController.js.map +1 -1
  52. package/dist/esm/snaps/constants.js +16 -0
  53. package/dist/esm/snaps/constants.js.map +1 -0
  54. package/dist/esm/snaps/index.js +0 -2
  55. package/dist/esm/snaps/index.js.map +1 -1
  56. package/dist/esm/snaps/location/npm.js +13 -2
  57. package/dist/esm/snaps/location/npm.js.map +1 -1
  58. package/dist/types/index.d.ts +1 -0
  59. package/dist/types/interface/SnapInterfaceController.d.ts +85 -0
  60. package/dist/types/interface/index.d.ts +1 -0
  61. package/dist/types/interface/utils.d.ts +36 -0
  62. package/dist/types/services/browser.d.ts +1 -0
  63. package/dist/types/services/index.d.ts +1 -0
  64. package/dist/types/services/webview/WebViewExecutionService.d.ts +20 -0
  65. package/dist/types/services/webview/WebViewMessageStream.d.ts +32 -0
  66. package/dist/types/services/webview/index.d.ts +1 -0
  67. package/dist/types/snaps/SnapController.d.ts +7 -4
  68. package/dist/types/snaps/constants.d.ts +1 -0
  69. package/dist/types/snaps/index.d.ts +0 -2
  70. package/dist/types/utils.d.ts +33 -13
  71. package/package.json +11 -11
  72. package/dist/cjs/snaps/endowments/cronjob.js +0 -100
  73. package/dist/cjs/snaps/endowments/cronjob.js.map +0 -1
  74. package/dist/cjs/snaps/endowments/enum.js +0 -26
  75. package/dist/cjs/snaps/endowments/enum.js.map +0 -1
  76. package/dist/cjs/snaps/endowments/ethereum-provider.js +0 -43
  77. package/dist/cjs/snaps/endowments/ethereum-provider.js.map +0 -1
  78. package/dist/cjs/snaps/endowments/home-page.js +0 -37
  79. package/dist/cjs/snaps/endowments/home-page.js.map +0 -1
  80. package/dist/cjs/snaps/endowments/index.js +0 -107
  81. package/dist/cjs/snaps/endowments/index.js.map +0 -1
  82. package/dist/cjs/snaps/endowments/keyring.js +0 -100
  83. package/dist/cjs/snaps/endowments/keyring.js.map +0 -1
  84. package/dist/cjs/snaps/endowments/lifecycle-hooks.js +0 -37
  85. package/dist/cjs/snaps/endowments/lifecycle-hooks.js.map +0 -1
  86. package/dist/cjs/snaps/endowments/name-lookup.js +0 -106
  87. package/dist/cjs/snaps/endowments/name-lookup.js.map +0 -1
  88. package/dist/cjs/snaps/endowments/network-access.js +0 -44
  89. package/dist/cjs/snaps/endowments/network-access.js.map +0 -1
  90. package/dist/cjs/snaps/endowments/rpc.js +0 -99
  91. package/dist/cjs/snaps/endowments/rpc.js.map +0 -1
  92. package/dist/cjs/snaps/endowments/signature-insight.js +0 -106
  93. package/dist/cjs/snaps/endowments/signature-insight.js.map +0 -1
  94. package/dist/cjs/snaps/endowments/transaction-insight.js +0 -106
  95. package/dist/cjs/snaps/endowments/transaction-insight.js.map +0 -1
  96. package/dist/cjs/snaps/endowments/web-assembly.js +0 -42
  97. package/dist/cjs/snaps/endowments/web-assembly.js.map +0 -1
  98. package/dist/cjs/snaps/permissions.js +0 -61
  99. package/dist/cjs/snaps/permissions.js.map +0 -1
  100. package/dist/esm/snaps/endowments/cronjob.js +0 -99
  101. package/dist/esm/snaps/endowments/cronjob.js.map +0 -1
  102. package/dist/esm/snaps/endowments/enum.js +0 -16
  103. package/dist/esm/snaps/endowments/enum.js.map +0 -1
  104. package/dist/esm/snaps/endowments/ethereum-provider.js +0 -33
  105. package/dist/esm/snaps/endowments/ethereum-provider.js.map +0 -1
  106. package/dist/esm/snaps/endowments/home-page.js +0 -27
  107. package/dist/esm/snaps/endowments/home-page.js.map +0 -1
  108. package/dist/esm/snaps/endowments/index.js +0 -60
  109. package/dist/esm/snaps/endowments/index.js.map +0 -1
  110. package/dist/esm/snaps/endowments/keyring.js +0 -91
  111. package/dist/esm/snaps/endowments/keyring.js.map +0 -1
  112. package/dist/esm/snaps/endowments/lifecycle-hooks.js +0 -27
  113. package/dist/esm/snaps/endowments/lifecycle-hooks.js.map +0 -1
  114. package/dist/esm/snaps/endowments/name-lookup.js +0 -98
  115. package/dist/esm/snaps/endowments/name-lookup.js.map +0 -1
  116. package/dist/esm/snaps/endowments/network-access.js +0 -34
  117. package/dist/esm/snaps/endowments/network-access.js.map +0 -1
  118. package/dist/esm/snaps/endowments/rpc.js +0 -88
  119. package/dist/esm/snaps/endowments/rpc.js.map +0 -1
  120. package/dist/esm/snaps/endowments/signature-insight.js +0 -99
  121. package/dist/esm/snaps/endowments/signature-insight.js.map +0 -1
  122. package/dist/esm/snaps/endowments/transaction-insight.js +0 -99
  123. package/dist/esm/snaps/endowments/transaction-insight.js.map +0 -1
  124. package/dist/esm/snaps/endowments/web-assembly.js +0 -32
  125. package/dist/esm/snaps/endowments/web-assembly.js.map +0 -1
  126. package/dist/esm/snaps/permissions.js +0 -50
  127. package/dist/esm/snaps/permissions.js.map +0 -1
  128. package/dist/types/snaps/endowments/cronjob.d.ts +0 -51
  129. package/dist/types/snaps/endowments/enum.d.ts +0 -13
  130. package/dist/types/snaps/endowments/ethereum-provider.d.ts +0 -14
  131. package/dist/types/snaps/endowments/home-page.d.ts +0 -15
  132. package/dist/types/snaps/endowments/index.d.ts +0 -127
  133. package/dist/types/snaps/endowments/keyring.d.ts +0 -39
  134. package/dist/types/snaps/endowments/lifecycle-hooks.d.ts +0 -15
  135. package/dist/types/snaps/endowments/name-lookup.d.ts +0 -38
  136. package/dist/types/snaps/endowments/network-access.d.ts +0 -14
  137. package/dist/types/snaps/endowments/rpc.d.ts +0 -38
  138. package/dist/types/snaps/endowments/signature-insight.d.ts +0 -39
  139. package/dist/types/snaps/endowments/transaction-insight.d.ts +0 -39
  140. package/dist/types/snaps/endowments/web-assembly.d.ts +0 -14
  141. package/dist/types/snaps/permissions.d.ts +0 -16
@@ -0,0 +1,127 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", {
3
+ value: true
4
+ });
5
+ Object.defineProperty(exports, "WebViewMessageStream", {
6
+ enumerable: true,
7
+ get: function() {
8
+ return WebViewMessageStream;
9
+ }
10
+ });
11
+ const _postmessagestream = require("@metamask/post-message-stream");
12
+ const _utils = require("@metamask/post-message-stream/dist/utils");
13
+ const _snapsutils = require("@metamask/snaps-utils");
14
+ const _utils1 = require("@metamask/utils");
15
+ function _check_private_redeclaration(obj, privateCollection) {
16
+ if (privateCollection.has(obj)) {
17
+ throw new TypeError("Cannot initialize the same private elements twice on an object");
18
+ }
19
+ }
20
+ function _class_apply_descriptor_get(receiver, descriptor) {
21
+ if (descriptor.get) {
22
+ return descriptor.get.call(receiver);
23
+ }
24
+ return descriptor.value;
25
+ }
26
+ function _class_apply_descriptor_set(receiver, descriptor, value) {
27
+ if (descriptor.set) {
28
+ descriptor.set.call(receiver, value);
29
+ } else {
30
+ if (!descriptor.writable) {
31
+ throw new TypeError("attempted to set read only private field");
32
+ }
33
+ descriptor.value = value;
34
+ }
35
+ }
36
+ function _class_extract_field_descriptor(receiver, privateMap, action) {
37
+ if (!privateMap.has(receiver)) {
38
+ throw new TypeError("attempted to " + action + " private field on non-instance");
39
+ }
40
+ return privateMap.get(receiver);
41
+ }
42
+ function _class_private_field_get(receiver, privateMap) {
43
+ var descriptor = _class_extract_field_descriptor(receiver, privateMap, "get");
44
+ return _class_apply_descriptor_get(receiver, descriptor);
45
+ }
46
+ function _class_private_field_init(obj, privateMap, value) {
47
+ _check_private_redeclaration(obj, privateMap);
48
+ privateMap.set(obj, value);
49
+ }
50
+ function _class_private_field_set(receiver, privateMap, value) {
51
+ var descriptor = _class_extract_field_descriptor(receiver, privateMap, "set");
52
+ _class_apply_descriptor_set(receiver, descriptor, value);
53
+ return value;
54
+ }
55
+ var _name = /*#__PURE__*/ new WeakMap(), _target = /*#__PURE__*/ new WeakMap(), _webView = /*#__PURE__*/ new WeakMap();
56
+ class WebViewMessageStream extends _postmessagestream.BasePostMessageStream {
57
+ _postMessage(data) {
58
+ (0, _utils1.assert)(_class_private_field_get(this, _webView));
59
+ const json = JSON.stringify({
60
+ target: _class_private_field_get(this, _target),
61
+ data
62
+ });
63
+ // To prevent XSS, we base64 encode the message before injecting it.
64
+ // This adds significant performance overhead.
65
+ // TODO: Should we use mobile native base64 here?
66
+ const bytes = (0, _utils1.stringToBytes)(json);
67
+ const base64 = (0, _utils1.bytesToBase64)(bytes);
68
+ _class_private_field_get(this, _webView).injectJavaScript(`window.postMessage('${base64}')`);
69
+ }
70
+ _onMessage(event) {
71
+ if (typeof event.data !== 'string') {
72
+ return;
73
+ }
74
+ const message = JSON.parse(event.data);
75
+ // Notice that we don't check targetWindow or targetOrigin here.
76
+ // This doesn't seem possible to do in RN.
77
+ if (!(0, _utils.isValidStreamMessage)(message) || message.target !== _class_private_field_get(this, _name)) {
78
+ return;
79
+ }
80
+ this._onData(message.data);
81
+ }
82
+ _destroy() {
83
+ (0, _utils1.assert)(_class_private_field_get(this, _webView));
84
+ // This method is already bound.
85
+ // eslint-disable-next-line @typescript-eslint/unbound-method
86
+ _class_private_field_get(this, _webView).unregisterMessageListener(this._onMessage);
87
+ }
88
+ /**
89
+ * Creates a stream for communicating with other streams inside a WebView.
90
+ *
91
+ * @param args - Options bag.
92
+ * @param args.name - The name of the stream. Used to differentiate between
93
+ * multiple streams sharing the same window object.
94
+ * @param args.target - The name of the stream to exchange messages with.
95
+ * @param args.getWebView - A asynchronous getter for the webview.
96
+ */ constructor({ name, target, getWebView }){
97
+ super();
98
+ _class_private_field_init(this, _name, {
99
+ writable: true,
100
+ value: void 0
101
+ });
102
+ _class_private_field_init(this, _target, {
103
+ writable: true,
104
+ value: void 0
105
+ });
106
+ _class_private_field_init(this, _webView, {
107
+ writable: true,
108
+ value: void 0
109
+ });
110
+ _class_private_field_set(this, _name, name);
111
+ _class_private_field_set(this, _target, target);
112
+ this._onMessage = this._onMessage.bind(this);
113
+ // This is a bit atypical from other post-message streams.
114
+ // We have to wait for the WebView to fully load before we can continue using the stream.
115
+ getWebView().then((webView)=>{
116
+ _class_private_field_set(this, _webView, webView);
117
+ // This method is already bound.
118
+ // eslint-disable-next-line @typescript-eslint/unbound-method
119
+ webView.registerMessageListener(this._onMessage);
120
+ this._handshake();
121
+ }).catch((error)=>{
122
+ (0, _snapsutils.logError)(error);
123
+ });
124
+ }
125
+ }
126
+
127
+ //# sourceMappingURL=WebViewMessageStream.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../../../src/services/webview/WebViewMessageStream.ts"],"sourcesContent":["import type { PostMessageEvent } from '@metamask/post-message-stream';\nimport { BasePostMessageStream } from '@metamask/post-message-stream';\nimport { isValidStreamMessage } from '@metamask/post-message-stream/dist/utils';\nimport { logError } from '@metamask/snaps-utils';\nimport { assert, bytesToBase64, stringToBytes } from '@metamask/utils';\n\nexport type WebViewInterface = {\n injectJavaScript(js: string): void;\n registerMessageListener(listener: (event: PostMessageEvent) => void): void;\n unregisterMessageListener(listener: (event: PostMessageEvent) => void): void;\n};\n\ntype WebViewStreamArgs = {\n name: string;\n target: string;\n getWebView: () => Promise<WebViewInterface>;\n};\n\n/**\n * A special postMessage stream used to interface with a WebView.\n */\n\nexport class WebViewMessageStream extends BasePostMessageStream {\n #name;\n\n #target;\n\n #webView: WebViewInterface | undefined;\n\n /**\n * Creates a stream for communicating with other streams inside a WebView.\n *\n * @param args - Options bag.\n * @param args.name - The name of the stream. Used to differentiate between\n * multiple streams sharing the same window object.\n * @param args.target - The name of the stream to exchange messages with.\n * @param args.getWebView - A asynchronous getter for the webview.\n */\n constructor({ name, target, getWebView }: WebViewStreamArgs) {\n super();\n\n this.#name = name;\n this.#target = target;\n\n this._onMessage = this._onMessage.bind(this);\n\n // This is a bit atypical from other post-message streams.\n // We have to wait for the WebView to fully load before we can continue using the stream.\n getWebView()\n .then((webView) => {\n this.#webView = webView;\n // This method is already bound.\n // eslint-disable-next-line @typescript-eslint/unbound-method\n webView.registerMessageListener(this._onMessage);\n this._handshake();\n })\n .catch((error) => {\n logError(error);\n });\n }\n\n protected _postMessage(data: unknown): void {\n assert(this.#webView);\n const json = JSON.stringify({\n target: this.#target,\n data,\n });\n\n // To prevent XSS, we base64 encode the message before injecting it.\n // This adds significant performance overhead.\n // TODO: Should we use mobile native base64 here?\n const bytes = stringToBytes(json);\n const base64 = bytesToBase64(bytes);\n this.#webView.injectJavaScript(`window.postMessage('${base64}')`);\n }\n\n private _onMessage(event: PostMessageEvent): void {\n if (typeof event.data !== 'string') {\n return;\n }\n\n const message = JSON.parse(event.data);\n\n // Notice that we don't check targetWindow or targetOrigin here.\n // This doesn't seem possible to do in RN.\n if (!isValidStreamMessage(message) || message.target !== this.#name) {\n return;\n }\n\n this._onData(message.data);\n }\n\n _destroy() {\n assert(this.#webView);\n // This method is already bound.\n // eslint-disable-next-line @typescript-eslint/unbound-method\n this.#webView.unregisterMessageListener(this._onMessage);\n }\n}\n"],"names":["WebViewMessageStream","BasePostMessageStream","_postMessage","data","assert","webView","json","JSON","stringify","target","bytes","stringToBytes","base64","bytesToBase64","injectJavaScript","_onMessage","event","message","parse","isValidStreamMessage","name","_onData","_destroy","unregisterMessageListener","constructor","getWebView","bind","then","registerMessageListener","_handshake","catch","error","logError"],"mappings":";;;;+BAsBaA;;;eAAAA;;;mCArByB;uBACD;4BACZ;wBAC4B;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;IAmBnD,qCAEA,uCAEA;AALK,MAAMA,6BAA6BC,wCAAqB;IAuCnDC,aAAaC,IAAa,EAAQ;QAC1CC,IAAAA,cAAM,2BAAC,IAAI,EAAEC;QACb,MAAMC,OAAOC,KAAKC,SAAS,CAAC;YAC1BC,MAAM,2BAAE,IAAI,EAAEA;YACdN;QACF;QAEA,oEAAoE;QACpE,8CAA8C;QAC9C,iDAAiD;QACjD,MAAMO,QAAQC,IAAAA,qBAAa,EAACL;QAC5B,MAAMM,SAASC,IAAAA,qBAAa,EAACH;QAC7B,yBAAA,IAAI,EAAEL,UAAQS,gBAAgB,CAAC,CAAC,oBAAoB,EAAEF,OAAO,EAAE,CAAC;IAClE;IAEQG,WAAWC,KAAuB,EAAQ;QAChD,IAAI,OAAOA,MAAMb,IAAI,KAAK,UAAU;YAClC;QACF;QAEA,MAAMc,UAAUV,KAAKW,KAAK,CAACF,MAAMb,IAAI;QAErC,gEAAgE;QAChE,0CAA0C;QAC1C,IAAI,CAACgB,IAAAA,2BAAoB,EAACF,YAAYA,QAAQR,MAAM,8BAAK,IAAI,EAAEW,QAAM;YACnE;QACF;QAEA,IAAI,CAACC,OAAO,CAACJ,QAAQd,IAAI;IAC3B;IAEAmB,WAAW;QACTlB,IAAAA,cAAM,2BAAC,IAAI,EAAEC;QACb,gCAAgC;QAChC,6DAA6D;QAC7D,yBAAA,IAAI,EAAEA,UAAQkB,yBAAyB,CAAC,IAAI,CAACR,UAAU;IACzD;IApEA;;;;;;;;GAQC,GACDS,YAAY,EAAEJ,IAAI,EAAEX,MAAM,EAAEgB,UAAU,EAAqB,CAAE;QAC3D,KAAK;QAhBP,gCAAA;;mBAAA,KAAA;;QAEA,gCAAA;;mBAAA,KAAA;;QAEA,gCAAA;;mBAAA,KAAA;;uCAcQL,OAAOA;uCACPX,SAASA;QAEf,IAAI,CAACM,UAAU,GAAG,IAAI,CAACA,UAAU,CAACW,IAAI,CAAC,IAAI;QAE3C,0DAA0D;QAC1D,yFAAyF;QACzFD,aACGE,IAAI,CAAC,CAACtB;2CACCA,UAAUA;YAChB,gCAAgC;YAChC,6DAA6D;YAC7DA,QAAQuB,uBAAuB,CAAC,IAAI,CAACb,UAAU;YAC/C,IAAI,CAACc,UAAU;QACjB,GACCC,KAAK,CAAC,CAACC;YACNC,IAAAA,oBAAQ,EAACD;QACX;IACJ;AAuCF"}
@@ -0,0 +1,20 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", {
3
+ value: true
4
+ });
5
+ _export_star(require("./WebViewExecutionService"), exports);
6
+ function _export_star(from, to) {
7
+ Object.keys(from).forEach(function(k) {
8
+ if (k !== "default" && !Object.prototype.hasOwnProperty.call(to, k)) {
9
+ Object.defineProperty(to, k, {
10
+ enumerable: true,
11
+ get: function() {
12
+ return from[k];
13
+ }
14
+ });
15
+ }
16
+ });
17
+ return from;
18
+ }
19
+
20
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../../../src/services/webview/index.ts"],"sourcesContent":["export * from './WebViewExecutionService';\n"],"names":[],"mappings":";;;;qBAAc"}
@@ -37,11 +37,8 @@ const _nanoid = require("nanoid");
37
37
  const _fsm1 = require("../fsm");
38
38
  const _logging = require("../logging");
39
39
  const _utils1 = require("../utils");
40
- const _endowments = require("./endowments");
41
- const _keyring = require("./endowments/keyring");
42
- const _rpc = require("./endowments/rpc");
40
+ const _constants = require("./constants");
43
41
  const _location = require("./location");
44
- const _permissions = require("./permissions");
45
42
  const _registry = require("./registry");
46
43
  const _RequestQueue = require("./RequestQueue");
47
44
  const _Timer = require("./Timer");
@@ -190,11 +187,19 @@ _initializeStateMachine = /*#__PURE__*/ new WeakSet(), /**
190
187
  * @param args - The add snap args.
191
188
  * @returns The resulting snap object.
192
189
  */ _set = /*#__PURE__*/ new WeakSet(), _validateSnapPermissions = /*#__PURE__*/ new WeakSet(), /**
190
+ * Determine the execution timeout for a given handler permission.
191
+ *
192
+ * If no permission is specified or the permission itself has no execution timeout defined
193
+ * the constructor argument `maxRequestTime` will be used.
194
+ *
195
+ * @param permission - An optional permission constraint for the handler being called.
196
+ * @returns The execution timeout for the given handler.
197
+ */ _getExecutionTimeout = /*#__PURE__*/ new WeakSet(), /**
193
198
  * Gets the RPC message handler for the given snap.
194
199
  *
195
200
  * @param snapId - The id of the Snap whose message handler to get.
196
201
  * @returns The RPC handler for the given snap.
197
- */ _getRpcRequestHandler = /*#__PURE__*/ new WeakSet(), _triggerPhishingListUpdate = /*#__PURE__*/ new WeakSet(), _checkPhishingList = /*#__PURE__*/ new WeakSet(), _assertSnapRpcRequestResult = /*#__PURE__*/ new WeakSet(), _executeWithTimeout = /*#__PURE__*/ new WeakSet(), _recordSnapRpcRequestStart = /*#__PURE__*/ new WeakSet(), _recordSnapRpcRequestFinish = /*#__PURE__*/ new WeakSet(), /**
202
+ */ _getRpcRequestHandler = /*#__PURE__*/ new WeakSet(), _createInterface = /*#__PURE__*/ new WeakSet(), _assertInterfaceExists = /*#__PURE__*/ new WeakSet(), _transformSnapRpcRequestResult = /*#__PURE__*/ new WeakSet(), _assertSnapRpcRequestResult = /*#__PURE__*/ new WeakSet(), _executeWithTimeout = /*#__PURE__*/ new WeakSet(), _recordSnapRpcRequestStart = /*#__PURE__*/ new WeakSet(), _recordSnapRpcRequestFinish = /*#__PURE__*/ new WeakSet(), /**
198
203
  * Retrieves the rollback snapshot of a snap.
199
204
  *
200
205
  * @param snapId - The snap id.
@@ -786,9 +791,10 @@ class SnapController extends _basecontroller.BaseController {
786
791
  }
787
792
  await _class_private_method_get(this, _assertIsInstallAllowed, assertIsInstallAllowed).call(this, snapId, {
788
793
  version: newVersion,
789
- checksum: manifest.source.shasum
794
+ checksum: manifest.source.shasum,
795
+ permissions: manifest.initialPermissions
790
796
  });
791
- const processedPermissions = (0, _permissions.processSnapPermissions)(manifest.initialPermissions);
797
+ const processedPermissions = (0, _snapsrpcmethods.processSnapPermissions)(manifest.initialPermissions);
792
798
  _class_private_method_get(this, _validateSnapPermissions, validateSnapPermissions).call(this, processedPermissions);
793
799
  const { newPermissions, unusedPermissions, approvedPermissions } = _class_private_method_get(this, _calculatePermissionsChange, calculatePermissionsChange).call(this, snapId, processedPermissions);
794
800
  _class_private_method_get(this, _updateApproval, updateApproval).call(this, pendingApproval.id, {
@@ -885,7 +891,7 @@ class SnapController extends _basecontroller.BaseController {
885
891
  const snap = snapsState[snapId];
886
892
  const { initialPermissions } = snap;
887
893
  try {
888
- const processedPermissions = (0, _permissions.processSnapPermissions)(initialPermissions);
894
+ const processedPermissions = (0, _snapsrpcmethods.processSnapPermissions)(initialPermissions);
889
895
  _class_private_method_get(this, _validateSnapPermissions, validateSnapPermissions).call(this, processedPermissions);
890
896
  _class_private_method_get(this, _updateApproval, updateApproval).call(this, pendingApproval.id, {
891
897
  loading: false,
@@ -932,30 +938,33 @@ class SnapController extends _basecontroller.BaseController {
932
938
  ...rawRequest
933
939
  };
934
940
  (0, _utils.assertIsJsonRpcRequest)(request);
935
- const permissionName = _endowments.handlerEndowments[handlerType];
936
- const hasPermission = this.messagingSystem.call('PermissionController:hasPermission', snapId, permissionName);
937
- if (!hasPermission) {
941
+ const permissionName = _snapsrpcmethods.handlerEndowments[handlerType];
942
+ (0, _utils.assert)(typeof permissionName === 'string' || permissionName === null, "'permissionName' must be either a string or null.");
943
+ const permissions = this.messagingSystem.call('PermissionController:getPermissions', snapId);
944
+ // If permissionName is null, the handler does not require a permission.
945
+ if (permissionName !== null && (!permissions || !(0, _utils.hasProperty)(permissions, permissionName))) {
938
946
  throw new Error(`Snap "${snapId}" is not permitted to use "${permissionName}".`);
939
947
  }
940
- if (permissionName === _endowments.SnapEndowments.Rpc || permissionName === _endowments.SnapEndowments.Keyring) {
941
- const subject = this.messagingSystem.call('SubjectMetadataController:getSubjectMetadata', origin);
942
- const permissions = this.messagingSystem.call('PermissionController:getPermissions', snapId);
943
- const handlerPermissions = permissions?.[permissionName];
948
+ const handlerPermissions = permissionName ? permissions[permissionName] : undefined;
949
+ if (permissionName === _snapsrpcmethods.SnapEndowments.Rpc || permissionName === _snapsrpcmethods.SnapEndowments.Keyring) {
944
950
  (0, _utils.assert)(handlerPermissions);
945
- const origins = permissionName === _endowments.SnapEndowments.Rpc ? (0, _rpc.getRpcCaveatOrigins)(handlerPermissions) : (0, _keyring.getKeyringCaveatOrigins)(handlerPermissions);
951
+ const subject = this.messagingSystem.call('SubjectMetadataController:getSubjectMetadata', origin);
952
+ const origins = permissionName === _snapsrpcmethods.SnapEndowments.Rpc ? (0, _snapsrpcmethods.getRpcCaveatOrigins)(handlerPermissions) : (0, _snapsrpcmethods.getKeyringCaveatOrigins)(handlerPermissions);
946
953
  (0, _utils.assert)(origins);
947
954
  if (!(0, _snapsutils.isOriginAllowed)(origins, subject?.subjectType ?? _permissioncontroller.SubjectType.Website, origin)) {
948
955
  throw new Error(`Snap "${snapId}" is not permitted to handle requests from "${origin}".`);
949
956
  }
950
957
  }
951
- const handler = await _class_private_method_get(this, _getRpcRequestHandler, getRpcRequestHandler).call(this, snapId);
958
+ const handler = _class_private_method_get(this, _getRpcRequestHandler, getRpcRequestHandler).call(this, snapId);
952
959
  if (!handler) {
953
960
  throw new Error(`Snap RPC message handler not found for snap "${snapId}".`);
954
961
  }
962
+ const timeout = _class_private_method_get(this, _getExecutionTimeout, getExecutionTimeout).call(this, handlerPermissions);
955
963
  return handler({
956
964
  origin,
957
965
  handler: handlerType,
958
- request
966
+ request,
967
+ timeout
959
968
  });
960
969
  }
961
970
  constructor({ closeAllConnections, messenger, state, dynamicPermissions = [
@@ -1046,12 +1055,28 @@ class SnapController extends _basecontroller.BaseController {
1046
1055
  */ _class_private_method_init(this, _getEndowments);
1047
1056
  _class_private_method_init(this, _set);
1048
1057
  _class_private_method_init(this, _validateSnapPermissions);
1058
+ _class_private_method_init(this, _getExecutionTimeout);
1049
1059
  _class_private_method_init(this, _getRpcRequestHandler);
1050
- _class_private_method_init(this, _triggerPhishingListUpdate);
1051
- _class_private_method_init(this, _checkPhishingList);
1052
1060
  /**
1053
- * Asserts that the returned result of a Snap RPC call is the expected shape.
1061
+ * Create a dynamic interface in the SnapInterfaceController.
1062
+ *
1063
+ * @param snapId - The snap ID.
1064
+ * @param content - The initial interface content.
1065
+ * @returns An identifier that can be used to identify the interface.
1066
+ */ _class_private_method_init(this, _createInterface);
1067
+ _class_private_method_init(this, _assertInterfaceExists);
1068
+ /**
1069
+ * Transform a RPC request result if necessary.
1054
1070
  *
1071
+ * @param snapId - The snap ID of the snap that produced the result.
1072
+ * @param handlerType - The handler type that produced the result.
1073
+ * @param result - The result.
1074
+ * @returns The transformed result if applicable, otherwise the original result.
1075
+ */ _class_private_method_init(this, _transformSnapRpcRequestResult);
1076
+ /**
1077
+ * Assert that the returned result of a Snap RPC call is the expected shape.
1078
+ *
1079
+ * @param snapId - The snap ID.
1055
1080
  * @param handlerType - The handler type of the RPC Request.
1056
1081
  * @param result - The result of the RPC request.
1057
1082
  */ _class_private_method_init(this, _assertSnapRpcRequestResult);
@@ -1309,7 +1334,7 @@ function handlePreinstalledSnaps(preinstalledSnaps) {
1309
1334
  preinstalled: true
1310
1335
  });
1311
1336
  // Setup permissions
1312
- const processedPermissions = (0, _permissions.processSnapPermissions)(manifest.initialPermissions);
1337
+ const processedPermissions = (0, _snapsrpcmethods.processSnapPermissions)(manifest.initialPermissions);
1313
1338
  _class_private_method_get(this, _validateSnapPermissions, validateSnapPermissions).call(this, processedPermissions);
1314
1339
  const { newPermissions, unusedPermissions } = _class_private_method_get(this, _calculatePermissionsChange, calculatePermissionsChange).call(this, snapId, processedPermissions);
1315
1340
  _class_private_method_get(this, _updatePermissions, updatePermissions).call(this, {
@@ -1364,7 +1389,9 @@ async function assertIsInstallAllowed(snapId, snapInfo) {
1364
1389
  const result = results[snapId];
1365
1390
  if (result.status === _registry.SnapsRegistryStatus.Blocked) {
1366
1391
  throw new Error(`Cannot install version "${snapInfo.version}" of snap "${snapId}": The version is blocked. ${result.reason?.explanation ?? ''}`);
1367
- } else if (_class_private_field_get(this, _featureFlags).requireAllowlist && result.status !== _registry.SnapsRegistryStatus.Verified) {
1392
+ }
1393
+ const isAllowlistingRequired = Object.keys(snapInfo.permissions).some((permission)=>!_constants.ALLOWED_PERMISSIONS.includes(permission));
1394
+ if (_class_private_field_get(this, _featureFlags).requireAllowlist && isAllowlistingRequired && result.status !== _registry.SnapsRegistryStatus.Verified) {
1368
1395
  throw new Error(`Cannot install version "${snapInfo.version}" of snap "${snapId}": The snap is not on the allowlist.`);
1369
1396
  }
1370
1397
  }
@@ -1495,7 +1522,8 @@ async function add(args) {
1495
1522
  }
1496
1523
  await _class_private_method_get(this, _assertIsInstallAllowed, assertIsInstallAllowed).call(this, snapId, {
1497
1524
  version: manifest.version,
1498
- checksum: manifest.source.shasum
1525
+ checksum: manifest.source.shasum,
1526
+ permissions: manifest.initialPermissions
1499
1527
  });
1500
1528
  return _class_private_method_get(this, _set, set).call(this, {
1501
1529
  ...args,
@@ -1565,7 +1593,7 @@ function set(args) {
1565
1593
  const { id: snapId, origin, files, isUpdate = false, removable, preinstalled } = args;
1566
1594
  const { manifest, sourceCode: sourceCodeFile, svgIcon, auxiliaryFiles: rawAuxiliaryFiles, localizationFiles } = files;
1567
1595
  (0, _snapsutils.assertIsSnapManifest)(manifest.result);
1568
- const { version, proposedName } = manifest.result;
1596
+ const { version } = manifest.result;
1569
1597
  const sourceCode = sourceCodeFile.toString();
1570
1598
  (0, _utils.assert)(typeof sourceCode === 'string' && sourceCode.length > 0, `Invalid source code for snap "${snapId}".`);
1571
1599
  const auxiliaryFiles = rawAuxiliaryFiles.map((file)=>{
@@ -1586,6 +1614,7 @@ function set(args) {
1586
1614
  origin
1587
1615
  }
1588
1616
  ];
1617
+ const localizedFiles = localizationFiles.map((file)=>file.result);
1589
1618
  const snap = {
1590
1619
  // Restore relevant snap state if it exists
1591
1620
  ...existingSnap,
@@ -1603,7 +1632,7 @@ function set(args) {
1603
1632
  version,
1604
1633
  versionHistory,
1605
1634
  auxiliaryFiles,
1606
- localizationFiles: localizationFiles.map((file)=>file.result)
1635
+ localizationFiles: localizedFiles
1607
1636
  };
1608
1637
  // If the snap was blocked, it isn't any longer
1609
1638
  delete snap.blockInformation;
@@ -1619,6 +1648,9 @@ function set(args) {
1619
1648
  rollbackSnapshot.statePatches = inversePatches;
1620
1649
  }
1621
1650
  }
1651
+ // In case the Snap uses a localized manifest, we need to get the
1652
+ // proposed name from the localized manifest.
1653
+ const { proposedName } = (0, _snapsutils.getLocalizedSnapManifest)(manifest.result, 'en', localizedFiles);
1622
1654
  this.messagingSystem.call('SubjectMetadataController:addSubjectMetadata', {
1623
1655
  subjectType: _permissioncontroller.SubjectType.Snap,
1624
1656
  name: proposedName,
@@ -1633,8 +1665,8 @@ function set(args) {
1633
1665
  }
1634
1666
  function validateSnapPermissions(processedPermissions) {
1635
1667
  const permissionKeys = Object.keys(processedPermissions);
1636
- const handlerPermissions = Array.from(new Set(Object.values(_endowments.handlerEndowments)));
1637
- (0, _utils.assert)(permissionKeys.some((key)=>handlerPermissions.includes(key)), `A snap must request at least one of the following permissions: ${handlerPermissions.join(', ')}.`);
1668
+ const handlerPermissions = Array.from(new Set(Object.values(_snapsrpcmethods.handlerEndowments)));
1669
+ (0, _utils.assert)(permissionKeys.some((key)=>handlerPermissions.includes(key)), `A snap must request at least one of the following permissions: ${handlerPermissions.filter((handler)=>handler !== null).join(', ')}.`);
1638
1670
  const excludedPermissionErrors = permissionKeys.reduce((errors, permission)=>{
1639
1671
  if ((0, _utils.hasProperty)(_class_private_field_get(this, _excludedPermissions), permission)) {
1640
1672
  errors.push(_class_private_field_get(this, _excludedPermissions)[permission]);
@@ -1643,6 +1675,9 @@ function validateSnapPermissions(processedPermissions) {
1643
1675
  }, []);
1644
1676
  (0, _utils.assert)(excludedPermissionErrors.length === 0, `One or more permissions are not allowed:\n${excludedPermissionErrors.join('\n')}`);
1645
1677
  }
1678
+ function getExecutionTimeout(permission) {
1679
+ return (0, _snapsrpcmethods.getMaxRequestTimeCaveat)(permission) ?? this.maxRequestTime;
1680
+ }
1646
1681
  function getRpcRequestHandler(snapId) {
1647
1682
  const runtime = _class_private_method_get(this, _getRuntimeExpect, getRuntimeExpect).call(this, snapId);
1648
1683
  const existingHandler = runtime.rpcHandler;
@@ -1653,7 +1688,7 @@ function getRpcRequestHandler(snapId) {
1653
1688
  // We need to set up this promise map to map snapIds to their respective startPromises,
1654
1689
  // because otherwise we would lose context on the correct startPromise.
1655
1690
  const startPromises = new Map();
1656
- const rpcHandler = async ({ origin, handler: handlerType, request })=>{
1691
+ const rpcHandler = async ({ origin, handler: handlerType, request, timeout })=>{
1657
1692
  if (this.state.snaps[snapId].enabled === false) {
1658
1693
  throw new Error(`Snap "${snapId}" is disabled.`);
1659
1694
  }
@@ -1679,7 +1714,7 @@ function getRpcRequestHandler(snapId) {
1679
1714
  }
1680
1715
  }
1681
1716
  }
1682
- const timer = new _Timer.Timer(this.maxRequestTime);
1717
+ const timer = new _Timer.Timer(timeout);
1683
1718
  _class_private_method_get(this, _recordSnapRpcRequestStart, recordSnapRpcRequestStart).call(this, snapId, request.id, timer);
1684
1719
  const handleRpcRequestPromise = this.messagingSystem.call('ExecutionService:handleRpcRequest', snapId, {
1685
1720
  origin,
@@ -1689,8 +1724,8 @@ function getRpcRequestHandler(snapId) {
1689
1724
  // This will either get the result or reject due to the timeout.
1690
1725
  try {
1691
1726
  const result = await _class_private_method_get(this, _executeWithTimeout, executeWithTimeout).call(this, handleRpcRequestPromise, timer);
1692
- await _class_private_method_get(this, _assertSnapRpcRequestResult, assertSnapRpcRequestResult).call(this, handlerType, result);
1693
- return result;
1727
+ await _class_private_method_get(this, _assertSnapRpcRequestResult, assertSnapRpcRequestResult).call(this, snapId, handlerType, result);
1728
+ return _class_private_method_get(this, _transformSnapRpcRequestResult, transformSnapRpcRequestResult).call(this, snapId, handlerType, result);
1694
1729
  } catch (error) {
1695
1730
  const [jsonRpcError, handled] = (0, _snapsutils.unwrapError)(error);
1696
1731
  if (!handled) {
@@ -1704,40 +1739,64 @@ function getRpcRequestHandler(snapId) {
1704
1739
  runtime.rpcHandler = rpcHandler;
1705
1740
  return rpcHandler;
1706
1741
  }
1707
- async function triggerPhishingListUpdate() {
1708
- return this.messagingSystem.call('PhishingController:maybeUpdateState');
1742
+ async function createInterface(snapId, content) {
1743
+ return this.messagingSystem.call('SnapInterfaceController:createInterface', snapId, content);
1709
1744
  }
1710
- function checkPhishingList(origin) {
1711
- return this.messagingSystem.call('PhishingController:testOrigin', origin).result;
1745
+ function assertInterfaceExists(snapId, id) {
1746
+ // This will throw if the interface isn't accessible, but we assert nevertheless.
1747
+ (0, _utils.assert)(this.messagingSystem.call('SnapInterfaceController:getInterface', snapId, id));
1712
1748
  }
1713
- async function assertSnapRpcRequestResult(handlerType, result) {
1749
+ async function transformSnapRpcRequestResult(snapId, handlerType, result) {
1750
+ switch(handlerType){
1751
+ case _snapsutils.HandlerType.OnTransaction:
1752
+ case _snapsutils.HandlerType.OnSignature:
1753
+ case _snapsutils.HandlerType.OnHomePage:
1754
+ {
1755
+ // Since this type has been asserted earlier we can cast
1756
+ const castResult = result;
1757
+ // If a handler returns static content, we turn it into a dynamic UI
1758
+ if (castResult && (0, _utils.hasProperty)(castResult, 'content')) {
1759
+ const { content, ...rest } = castResult;
1760
+ const id = await _class_private_method_get(this, _createInterface, createInterface).call(this, snapId, content);
1761
+ return {
1762
+ ...rest,
1763
+ id
1764
+ };
1765
+ }
1766
+ return result;
1767
+ }
1768
+ default:
1769
+ return result;
1770
+ }
1771
+ }
1772
+ async function assertSnapRpcRequestResult(snapId, handlerType, result) {
1714
1773
  switch(handlerType){
1715
1774
  case _snapsutils.HandlerType.OnTransaction:
1716
1775
  {
1717
1776
  (0, _utils.assertStruct)(result, _snapsutils.OnTransactionResponseStruct);
1718
- // Null is an allowed return value here
1719
- if (result === null) {
1720
- return;
1777
+ if (result && (0, _utils.hasProperty)(result, 'id')) {
1778
+ _class_private_method_get(this, _assertInterfaceExists, assertInterfaceExists).call(this, snapId, result.id);
1721
1779
  }
1722
- await _class_private_method_get(this, _triggerPhishingListUpdate, triggerPhishingListUpdate).call(this);
1723
- (0, _snapsutils.validateComponentLinks)(result.content, _class_private_method_get(this, _checkPhishingList, checkPhishingList).bind(this));
1724
1780
  break;
1725
1781
  }
1726
1782
  case _snapsutils.HandlerType.OnSignature:
1727
1783
  {
1728
1784
  (0, _utils.assertStruct)(result, _snapsutils.OnSignatureResponseStruct);
1729
- // Null is an allowed return value here
1730
- if (result === null) {
1731
- return;
1785
+ if (result && (0, _utils.hasProperty)(result, 'id')) {
1786
+ _class_private_method_get(this, _assertInterfaceExists, assertInterfaceExists).call(this, snapId, result.id);
1732
1787
  }
1733
- await _class_private_method_get(this, _triggerPhishingListUpdate, triggerPhishingListUpdate).call(this);
1734
- (0, _snapsutils.validateComponentLinks)(result.content, _class_private_method_get(this, _checkPhishingList, checkPhishingList).bind(this));
1735
1788
  break;
1736
1789
  }
1737
1790
  case _snapsutils.HandlerType.OnHomePage:
1738
- (0, _utils.assertStruct)(result, _snapsutils.OnHomePageResponseStruct);
1739
- await _class_private_method_get(this, _triggerPhishingListUpdate, triggerPhishingListUpdate).call(this);
1740
- (0, _snapsutils.validateComponentLinks)(result.content, _class_private_method_get(this, _checkPhishingList, checkPhishingList).bind(this));
1791
+ {
1792
+ (0, _utils.assertStruct)(result, _snapsutils.OnHomePageResponseStruct);
1793
+ if (result && (0, _utils.hasProperty)(result, 'id')) {
1794
+ _class_private_method_get(this, _assertInterfaceExists, assertInterfaceExists).call(this, snapId, result.id);
1795
+ }
1796
+ break;
1797
+ }
1798
+ case _snapsutils.HandlerType.OnNameLookup:
1799
+ (0, _utils.assertStruct)(result, _snapsutils.OnNameLookupResponseStruct);
1741
1800
  break;
1742
1801
  default:
1743
1802
  break;
@@ -1889,7 +1948,8 @@ function isValidUpdate(snapId, newVersionRange) {
1889
1948
  return true;
1890
1949
  }
1891
1950
  async function callLifecycleHook(snapId, handler) {
1892
- const permissionName = _endowments.handlerEndowments[handler];
1951
+ const permissionName = _snapsrpcmethods.handlerEndowments[handler];
1952
+ (0, _utils.assert)(permissionName, 'Lifecycle hook must have an endowment.');
1893
1953
  const hasPermission = this.messagingSystem.call('PermissionController:hasPermission', snapId, permissionName);
1894
1954
  if (!hasPermission) {
1895
1955
  return;