@metamask/snaps-utils 7.1.0 → 7.3.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.
- package/CHANGELOG.md +15 -1
- package/dist/{chunk-YP3ZXUME.mjs → chunk-2OJY3BXD.mjs} +3 -3
- package/dist/{chunk-MKTAIEG7.js → chunk-4LELSKWG.js} +3 -3
- package/dist/chunk-7VJ2BOVU.js +15 -0
- package/dist/chunk-7VJ2BOVU.js.map +1 -0
- package/dist/{chunk-7EDRFEUH.js → chunk-D7Z3SN2N.js} +7 -7
- package/dist/{chunk-X44Z53IG.js → chunk-G6BVXNNZ.js} +3 -3
- package/dist/{chunk-I77AVJKV.mjs → chunk-L4DKSTK6.mjs} +5 -5
- package/dist/chunk-L4DKSTK6.mjs.map +1 -0
- package/dist/{chunk-7Y3WSN44.mjs → chunk-LBCPJOAV.mjs} +2 -2
- package/dist/{chunk-E6U344HR.mjs → chunk-PBSBESZZ.mjs} +2 -2
- package/dist/{chunk-LSPOXPJJ.mjs → chunk-PWLXPALG.mjs} +2 -2
- package/dist/{chunk-AFQY2CNY.js → chunk-R5DO7T2D.js} +3 -3
- package/dist/chunk-UNNEBOL4.mjs +15 -0
- package/dist/chunk-UNNEBOL4.mjs.map +1 -0
- package/dist/{chunk-LBRWAC27.js → chunk-VDJTPG6F.js} +3 -3
- package/dist/{chunk-WEOCOYES.mjs → chunk-WZ457PEQ.mjs} +2 -2
- package/dist/chunk-YACE3IOJ.mjs +262 -0
- package/dist/chunk-YACE3IOJ.mjs.map +1 -0
- package/dist/chunk-YAKDZ5LP.js +262 -0
- package/dist/chunk-YAKDZ5LP.js.map +1 -0
- package/dist/{chunk-3SOYDY4W.js → chunk-ZUSNAQJU.js} +4 -4
- package/dist/chunk-ZUSNAQJU.js.map +1 -0
- package/dist/eval.js +4 -4
- package/dist/eval.mjs +3 -3
- package/dist/fs.js +3 -3
- package/dist/fs.mjs +2 -2
- package/dist/handlers.js +2 -2
- package/dist/handlers.mjs +1 -1
- package/dist/index.executionenv.js +2 -2
- package/dist/index.executionenv.mjs +1 -1
- package/dist/index.js +18 -8
- package/dist/index.mjs +22 -12
- package/dist/json.js +4 -2
- package/dist/json.mjs +3 -1
- package/dist/localization.js +3 -3
- package/dist/localization.mjs +2 -2
- package/dist/manifest/manifest.js +5 -5
- package/dist/manifest/manifest.mjs +4 -4
- package/dist/manifest/node.js +5 -5
- package/dist/manifest/node.mjs +4 -4
- package/dist/node.js +21 -11
- package/dist/node.mjs +24 -14
- package/dist/npm.js +5 -5
- package/dist/npm.mjs +4 -4
- package/dist/tsconfig.build.tsbuildinfo +1 -1
- package/dist/types/handlers.d.ts +89 -89
- package/dist/types/json.d.ts +9 -0
- package/dist/types/ui.d.ts +51 -11
- package/dist/ui.js +10 -2
- package/dist/ui.mjs +13 -5
- package/dist/validation.js +4 -4
- package/dist/validation.mjs +3 -3
- package/package.json +3 -3
- package/dist/chunk-3SOYDY4W.js.map +0 -1
- package/dist/chunk-6CHO3LOX.mjs +0 -10
- package/dist/chunk-6CHO3LOX.mjs.map +0 -1
- package/dist/chunk-HF7HUZ5Z.js +0 -10
- package/dist/chunk-HF7HUZ5Z.js.map +0 -1
- package/dist/chunk-I77AVJKV.mjs.map +0 -1
- package/dist/chunk-KP4ZAWMP.mjs +0 -80
- package/dist/chunk-KP4ZAWMP.mjs.map +0 -1
- package/dist/chunk-NDIITWO4.js +0 -80
- package/dist/chunk-NDIITWO4.js.map +0 -1
- /package/dist/{chunk-YP3ZXUME.mjs.map → chunk-2OJY3BXD.mjs.map} +0 -0
- /package/dist/{chunk-MKTAIEG7.js.map → chunk-4LELSKWG.js.map} +0 -0
- /package/dist/{chunk-7EDRFEUH.js.map → chunk-D7Z3SN2N.js.map} +0 -0
- /package/dist/{chunk-X44Z53IG.js.map → chunk-G6BVXNNZ.js.map} +0 -0
- /package/dist/{chunk-7Y3WSN44.mjs.map → chunk-LBCPJOAV.mjs.map} +0 -0
- /package/dist/{chunk-E6U344HR.mjs.map → chunk-PBSBESZZ.mjs.map} +0 -0
- /package/dist/{chunk-LBRWAC27.js.map → chunk-PWLXPALG.mjs.map} +0 -0
- /package/dist/{chunk-AFQY2CNY.js.map → chunk-R5DO7T2D.js.map} +0 -0
- /package/dist/{chunk-LSPOXPJJ.mjs.map → chunk-VDJTPG6F.js.map} +0 -0
- /package/dist/{chunk-WEOCOYES.mjs.map → chunk-WZ457PEQ.mjs.map} +0 -0
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/handlers.ts"],"sourcesContent":["import type {\n OnCronjobHandler,\n OnHomePageHandler,\n OnInstallHandler,\n OnKeyringRequestHandler,\n OnNameLookupHandler,\n OnRpcRequestHandler,\n OnSignatureHandler,\n OnTransactionHandler,\n OnUpdateHandler,\n OnUserInputHandler,\n} from '@metamask/snaps-sdk';\nimport { SeverityLevel, ComponentStruct } from '@metamask/snaps-sdk';\nimport {\n assign,\n literal,\n nullable,\n object,\n optional,\n string,\n array,\n size,\n union,\n} from 'superstruct';\n\nimport type { SnapHandler } from './handler-types';\nimport { HandlerType } from './handler-types';\n\nexport type SnapRpcHookArgs = {\n origin: string;\n handler: HandlerType;\n request: Record<string, unknown>;\n};\n\nexport const SNAP_EXPORTS = {\n [HandlerType.OnRpcRequest]: {\n type: HandlerType.OnRpcRequest,\n required: true,\n validator: (snapExport: unknown): snapExport is OnRpcRequestHandler => {\n return typeof snapExport === 'function';\n },\n },\n [HandlerType.OnTransaction]: {\n type: HandlerType.OnTransaction,\n required: true,\n validator: (snapExport: unknown): snapExport is OnTransactionHandler => {\n return typeof snapExport === 'function';\n },\n },\n [HandlerType.OnCronjob]: {\n type: HandlerType.OnCronjob,\n required: true,\n validator: (snapExport: unknown): snapExport is OnCronjobHandler => {\n return typeof snapExport === 'function';\n },\n },\n [HandlerType.OnNameLookup]: {\n type: HandlerType.OnNameLookup,\n required: true,\n validator: (snapExport: unknown): snapExport is OnNameLookupHandler => {\n return typeof snapExport === 'function';\n },\n },\n [HandlerType.OnInstall]: {\n type: HandlerType.OnInstall,\n required: false,\n validator: (snapExport: unknown): snapExport is OnInstallHandler => {\n return typeof snapExport === 'function';\n },\n },\n [HandlerType.OnUpdate]: {\n type: HandlerType.OnUpdate,\n required: false,\n validator: (snapExport: unknown): snapExport is OnUpdateHandler => {\n return typeof snapExport === 'function';\n },\n },\n [HandlerType.OnKeyringRequest]: {\n type: HandlerType.OnKeyringRequest,\n required: true,\n validator: (snapExport: unknown): snapExport is OnKeyringRequestHandler => {\n return typeof snapExport === 'function';\n },\n },\n [HandlerType.OnHomePage]: {\n type: HandlerType.OnHomePage,\n required: true,\n validator: (snapExport: unknown): snapExport is OnHomePageHandler => {\n return typeof snapExport === 'function';\n },\n },\n [HandlerType.OnSignature]: {\n type: HandlerType.OnSignature,\n required: true,\n validator: (snapExport: unknown): snapExport is OnSignatureHandler => {\n return typeof snapExport === 'function';\n },\n },\n [HandlerType.OnUserInput]: {\n type: HandlerType.OnUserInput,\n required: true,\n validator: (snapExport: unknown): snapExport is OnUserInputHandler => {\n return typeof snapExport === 'function';\n },\n },\n} as const;\n\nexport const OnTransactionSeverityResponseStruct = object({\n severity: optional(literal(SeverityLevel.Critical)),\n});\n\nexport const OnTransactionResponseWithIdStruct = assign(\n OnTransactionSeverityResponseStruct,\n object({\n id: string(),\n }),\n);\n\nexport const OnTransactionResponseWithContentStruct = assign(\n OnTransactionSeverityResponseStruct,\n object({\n content: ComponentStruct,\n }),\n);\n\nexport const OnTransactionResponseStruct = nullable(\n union([\n OnTransactionResponseWithContentStruct,\n OnTransactionResponseWithIdStruct,\n ]),\n);\n\nexport const OnSignatureResponseStruct = OnTransactionResponseStruct;\n\nexport const OnHomePageResponseWithContentStruct = object({\n content: ComponentStruct,\n});\n\nexport const OnHomePageResponseWithIdStruct = object({\n id: string(),\n});\n\nexport const OnHomePageResponseStruct = union([\n OnHomePageResponseWithContentStruct,\n OnHomePageResponseWithIdStruct,\n]);\n\nexport const AddressResolutionStruct = object({\n protocol: string(),\n resolvedDomain: string(),\n});\n\nexport const DomainResolutionStruct = object({\n protocol: string(),\n resolvedAddress: string(),\n});\n\nexport const AddressResolutionResponseStruct = object({\n resolvedDomains: size(array(AddressResolutionStruct), 1, Infinity),\n});\n\nexport const DomainResolutionResponseStruct = object({\n resolvedAddresses: size(array(DomainResolutionStruct), 1, Infinity),\n});\n\nexport const OnNameLookupResponseStruct = nullable(\n union([AddressResolutionResponseStruct, DomainResolutionResponseStruct]),\n);\n\n/**\n * Utility type for getting the handler function type from a handler type.\n */\nexport type HandlerFunction<Type extends SnapHandler> =\n Type['validator'] extends (snapExport: unknown) => snapExport is infer Handler\n ? Handler\n : never;\n\n/**\n * All the function-based handlers that a snap can implement.\n */\nexport type SnapFunctionExports = {\n [Key in keyof typeof SNAP_EXPORTS]?: HandlerFunction<\n (typeof SNAP_EXPORTS)[Key]\n >;\n};\n\n/**\n * All handlers that a snap can implement.\n */\nexport type SnapExports = SnapFunctionExports;\n"],"mappings":"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","names":[]}
|
package/dist/chunk-KP4ZAWMP.mjs
DELETED
|
@@ -1,80 +0,0 @@
|
|
|
1
|
-
// src/ui.ts
|
|
2
|
-
import { NodeType } from "@metamask/snaps-sdk";
|
|
3
|
-
import { assert, AssertionError, hasProperty } from "@metamask/utils";
|
|
4
|
-
import { lexer, walkTokens } from "marked";
|
|
5
|
-
var ALLOWED_PROTOCOLS = ["https:", "mailto:"];
|
|
6
|
-
function getMarkdownLinks(text) {
|
|
7
|
-
const tokens = lexer(text, { gfm: false });
|
|
8
|
-
const links = [];
|
|
9
|
-
walkTokens(tokens, (token) => {
|
|
10
|
-
if (token.type === "link") {
|
|
11
|
-
links.push(token);
|
|
12
|
-
}
|
|
13
|
-
});
|
|
14
|
-
return links.map((link) => link?.href).filter(Boolean);
|
|
15
|
-
}
|
|
16
|
-
function validateTextLinks(text, isOnPhishingList) {
|
|
17
|
-
const links = getMarkdownLinks(text);
|
|
18
|
-
for (const link of links) {
|
|
19
|
-
try {
|
|
20
|
-
const url = new URL(link);
|
|
21
|
-
assert(
|
|
22
|
-
ALLOWED_PROTOCOLS.includes(url.protocol),
|
|
23
|
-
`Protocol must be one of: ${ALLOWED_PROTOCOLS.join(", ")}.`
|
|
24
|
-
);
|
|
25
|
-
const hostname = url.protocol === "mailto:" ? url.pathname.split("@")[1] : url.hostname;
|
|
26
|
-
assert(!isOnPhishingList(hostname), "The specified URL is not allowed.");
|
|
27
|
-
} catch (error) {
|
|
28
|
-
throw new Error(
|
|
29
|
-
`Invalid URL: ${error instanceof AssertionError ? error.message : "Unable to parse URL."}`
|
|
30
|
-
);
|
|
31
|
-
}
|
|
32
|
-
}
|
|
33
|
-
}
|
|
34
|
-
function validateComponentLinks(component, isOnPhishingList) {
|
|
35
|
-
const { type } = component;
|
|
36
|
-
switch (type) {
|
|
37
|
-
case NodeType.Panel:
|
|
38
|
-
component.children.forEach(
|
|
39
|
-
(node) => validateComponentLinks(node, isOnPhishingList)
|
|
40
|
-
);
|
|
41
|
-
break;
|
|
42
|
-
case NodeType.Row:
|
|
43
|
-
validateComponentLinks(component.value, isOnPhishingList);
|
|
44
|
-
break;
|
|
45
|
-
case NodeType.Text:
|
|
46
|
-
validateTextLinks(component.value, isOnPhishingList);
|
|
47
|
-
break;
|
|
48
|
-
default:
|
|
49
|
-
break;
|
|
50
|
-
}
|
|
51
|
-
}
|
|
52
|
-
function getTotalTextLength(component) {
|
|
53
|
-
const { type } = component;
|
|
54
|
-
switch (type) {
|
|
55
|
-
case NodeType.Panel:
|
|
56
|
-
return component.children.reduce(
|
|
57
|
-
// This is a bug in TypeScript: https://github.com/microsoft/TypeScript/issues/48313
|
|
58
|
-
// eslint-disable-next-line @typescript-eslint/restrict-plus-operands
|
|
59
|
-
(sum, node) => sum + getTotalTextLength(node),
|
|
60
|
-
0
|
|
61
|
-
);
|
|
62
|
-
case NodeType.Row:
|
|
63
|
-
return getTotalTextLength(component.value);
|
|
64
|
-
case NodeType.Text:
|
|
65
|
-
return component.value.length;
|
|
66
|
-
default:
|
|
67
|
-
return 0;
|
|
68
|
-
}
|
|
69
|
-
}
|
|
70
|
-
function hasChildren(component) {
|
|
71
|
-
return hasProperty(component, "children");
|
|
72
|
-
}
|
|
73
|
-
|
|
74
|
-
export {
|
|
75
|
-
validateTextLinks,
|
|
76
|
-
validateComponentLinks,
|
|
77
|
-
getTotalTextLength,
|
|
78
|
-
hasChildren
|
|
79
|
-
};
|
|
80
|
-
//# sourceMappingURL=chunk-KP4ZAWMP.mjs.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/ui.ts"],"sourcesContent":["import type { Component, NodeWithChildren } from '@metamask/snaps-sdk';\nimport { NodeType } from '@metamask/snaps-sdk';\nimport { assert, AssertionError, hasProperty } from '@metamask/utils';\nimport type { Tokens } from 'marked';\nimport { lexer, walkTokens } from 'marked';\n\nconst ALLOWED_PROTOCOLS = ['https:', 'mailto:'];\n\n/**\n * Extract all links from a Markdown text string using the `marked` lexer.\n *\n * @param text - The markdown text string.\n * @returns A list of URLs linked to in the string.\n */\nfunction getMarkdownLinks(text: string) {\n const tokens = lexer(text, { gfm: false });\n const links: (Tokens.Link | Tokens.Generic)[] = [];\n\n // Walk the lexed tokens and collect all link tokens\n walkTokens(tokens, (token) => {\n if (token.type === 'link') {\n links.push(token);\n }\n });\n\n return links.map((link) => link?.href).filter(Boolean);\n}\n\n/**\n * Searches for markdown links in a string and checks them against the phishing list.\n *\n * @param text - The text to verify.\n * @param isOnPhishingList - The function that checks the link against the\n * phishing list.\n * @throws If the text contains a link that is not allowed.\n */\nexport function validateTextLinks(\n text: string,\n isOnPhishingList: (url: string) => boolean,\n) {\n const links = getMarkdownLinks(text);\n\n for (const link of links) {\n try {\n const url = new URL(link);\n assert(\n ALLOWED_PROTOCOLS.includes(url.protocol),\n `Protocol must be one of: ${ALLOWED_PROTOCOLS.join(', ')}.`,\n );\n\n const hostname =\n url.protocol === 'mailto:' ? url.pathname.split('@')[1] : url.hostname;\n\n assert(!isOnPhishingList(hostname), 'The specified URL is not allowed.');\n } catch (error) {\n throw new Error(\n `Invalid URL: ${\n error instanceof AssertionError\n ? error.message\n : 'Unable to parse URL.'\n }`,\n );\n }\n }\n}\n\n/**\n * Search for links in UI components and check that the URL they are trying to\n * pass in is not in the phishing list.\n *\n * @param component - The custom UI component.\n * @param isOnPhishingList - The function that checks the link against the\n * phishing list.\n * @throws If the component contains a link that is not allowed.\n */\nexport function validateComponentLinks(\n component: Component,\n isOnPhishingList: (url: string) => boolean,\n) {\n const { type } = component;\n switch (type) {\n case NodeType.Panel:\n component.children.forEach((node) =>\n validateComponentLinks(node, isOnPhishingList),\n );\n break;\n case NodeType.Row:\n validateComponentLinks(component.value, isOnPhishingList);\n break;\n case NodeType.Text:\n validateTextLinks(component.value, isOnPhishingList);\n break;\n default:\n break;\n }\n}\n\n/**\n * Calculate the total length of all text in the component.\n *\n * @param component - A custom UI component.\n * @returns The total length of all text components in the component.\n */\nexport function getTotalTextLength(component: Component): number {\n const { type } = component;\n\n switch (type) {\n case NodeType.Panel:\n return component.children.reduce<number>(\n // This is a bug in TypeScript: https://github.com/microsoft/TypeScript/issues/48313\n // eslint-disable-next-line @typescript-eslint/restrict-plus-operands\n (sum, node) => sum + getTotalTextLength(node),\n 0,\n );\n case NodeType.Row:\n return getTotalTextLength(component.value);\n case NodeType.Text:\n return component.value.length;\n default:\n return 0;\n }\n}\n\n/**\n * Check if a component has children.\n *\n * @param component - A custom UI component.\n * @returns `true` if the component has children, `false` otherwise.\n */\nexport function hasChildren(\n component: Component,\n): component is NodeWithChildren {\n return hasProperty(component, 'children');\n}\n"],"mappings":";AACA,SAAS,gBAAgB;AACzB,SAAS,QAAQ,gBAAgB,mBAAmB;AAEpD,SAAS,OAAO,kBAAkB;AAElC,IAAM,oBAAoB,CAAC,UAAU,SAAS;AAQ9C,SAAS,iBAAiB,MAAc;AACtC,QAAM,SAAS,MAAM,MAAM,EAAE,KAAK,MAAM,CAAC;AACzC,QAAM,QAA0C,CAAC;AAGjD,aAAW,QAAQ,CAAC,UAAU;AAC5B,QAAI,MAAM,SAAS,QAAQ;AACzB,YAAM,KAAK,KAAK;AAAA,IAClB;AAAA,EACF,CAAC;AAED,SAAO,MAAM,IAAI,CAAC,SAAS,MAAM,IAAI,EAAE,OAAO,OAAO;AACvD;AAUO,SAAS,kBACd,MACA,kBACA;AACA,QAAM,QAAQ,iBAAiB,IAAI;AAEnC,aAAW,QAAQ,OAAO;AACxB,QAAI;AACF,YAAM,MAAM,IAAI,IAAI,IAAI;AACxB;AAAA,QACE,kBAAkB,SAAS,IAAI,QAAQ;AAAA,QACvC,4BAA4B,kBAAkB,KAAK,IAAI,CAAC;AAAA,MAC1D;AAEA,YAAM,WACJ,IAAI,aAAa,YAAY,IAAI,SAAS,MAAM,GAAG,EAAE,CAAC,IAAI,IAAI;AAEhE,aAAO,CAAC,iBAAiB,QAAQ,GAAG,mCAAmC;AAAA,IACzE,SAAS,OAAO;AACd,YAAM,IAAI;AAAA,QACR,gBACE,iBAAiB,iBACb,MAAM,UACN,sBACN;AAAA,MACF;AAAA,IACF;AAAA,EACF;AACF;AAWO,SAAS,uBACd,WACA,kBACA;AACA,QAAM,EAAE,KAAK,IAAI;AACjB,UAAQ,MAAM;AAAA,IACZ,KAAK,SAAS;AACZ,gBAAU,SAAS;AAAA,QAAQ,CAAC,SAC1B,uBAAuB,MAAM,gBAAgB;AAAA,MAC/C;AACA;AAAA,IACF,KAAK,SAAS;AACZ,6BAAuB,UAAU,OAAO,gBAAgB;AACxD;AAAA,IACF,KAAK,SAAS;AACZ,wBAAkB,UAAU,OAAO,gBAAgB;AACnD;AAAA,IACF;AACE;AAAA,EACJ;AACF;AAQO,SAAS,mBAAmB,WAA8B;AAC/D,QAAM,EAAE,KAAK,IAAI;AAEjB,UAAQ,MAAM;AAAA,IACZ,KAAK,SAAS;AACZ,aAAO,UAAU,SAAS;AAAA;AAAA;AAAA,QAGxB,CAAC,KAAK,SAAS,MAAM,mBAAmB,IAAI;AAAA,QAC5C;AAAA,MACF;AAAA,IACF,KAAK,SAAS;AACZ,aAAO,mBAAmB,UAAU,KAAK;AAAA,IAC3C,KAAK,SAAS;AACZ,aAAO,UAAU,MAAM;AAAA,IACzB;AACE,aAAO;AAAA,EACX;AACF;AAQO,SAAS,YACd,WAC+B;AAC/B,SAAO,YAAY,WAAW,UAAU;AAC1C;","names":[]}
|
package/dist/chunk-NDIITWO4.js
DELETED
|
@@ -1,80 +0,0 @@
|
|
|
1
|
-
"use strict";Object.defineProperty(exports, "__esModule", {value: true});// src/ui.ts
|
|
2
|
-
var _snapssdk = require('@metamask/snaps-sdk');
|
|
3
|
-
var _utils = require('@metamask/utils');
|
|
4
|
-
var _marked = require('marked');
|
|
5
|
-
var ALLOWED_PROTOCOLS = ["https:", "mailto:"];
|
|
6
|
-
function getMarkdownLinks(text) {
|
|
7
|
-
const tokens = _marked.lexer.call(void 0, text, { gfm: false });
|
|
8
|
-
const links = [];
|
|
9
|
-
_marked.walkTokens.call(void 0, tokens, (token) => {
|
|
10
|
-
if (token.type === "link") {
|
|
11
|
-
links.push(token);
|
|
12
|
-
}
|
|
13
|
-
});
|
|
14
|
-
return links.map((link) => link?.href).filter(Boolean);
|
|
15
|
-
}
|
|
16
|
-
function validateTextLinks(text, isOnPhishingList) {
|
|
17
|
-
const links = getMarkdownLinks(text);
|
|
18
|
-
for (const link of links) {
|
|
19
|
-
try {
|
|
20
|
-
const url = new URL(link);
|
|
21
|
-
_utils.assert.call(void 0,
|
|
22
|
-
ALLOWED_PROTOCOLS.includes(url.protocol),
|
|
23
|
-
`Protocol must be one of: ${ALLOWED_PROTOCOLS.join(", ")}.`
|
|
24
|
-
);
|
|
25
|
-
const hostname = url.protocol === "mailto:" ? url.pathname.split("@")[1] : url.hostname;
|
|
26
|
-
_utils.assert.call(void 0, !isOnPhishingList(hostname), "The specified URL is not allowed.");
|
|
27
|
-
} catch (error) {
|
|
28
|
-
throw new Error(
|
|
29
|
-
`Invalid URL: ${error instanceof _utils.AssertionError ? error.message : "Unable to parse URL."}`
|
|
30
|
-
);
|
|
31
|
-
}
|
|
32
|
-
}
|
|
33
|
-
}
|
|
34
|
-
function validateComponentLinks(component, isOnPhishingList) {
|
|
35
|
-
const { type } = component;
|
|
36
|
-
switch (type) {
|
|
37
|
-
case _snapssdk.NodeType.Panel:
|
|
38
|
-
component.children.forEach(
|
|
39
|
-
(node) => validateComponentLinks(node, isOnPhishingList)
|
|
40
|
-
);
|
|
41
|
-
break;
|
|
42
|
-
case _snapssdk.NodeType.Row:
|
|
43
|
-
validateComponentLinks(component.value, isOnPhishingList);
|
|
44
|
-
break;
|
|
45
|
-
case _snapssdk.NodeType.Text:
|
|
46
|
-
validateTextLinks(component.value, isOnPhishingList);
|
|
47
|
-
break;
|
|
48
|
-
default:
|
|
49
|
-
break;
|
|
50
|
-
}
|
|
51
|
-
}
|
|
52
|
-
function getTotalTextLength(component) {
|
|
53
|
-
const { type } = component;
|
|
54
|
-
switch (type) {
|
|
55
|
-
case _snapssdk.NodeType.Panel:
|
|
56
|
-
return component.children.reduce(
|
|
57
|
-
// This is a bug in TypeScript: https://github.com/microsoft/TypeScript/issues/48313
|
|
58
|
-
// eslint-disable-next-line @typescript-eslint/restrict-plus-operands
|
|
59
|
-
(sum, node) => sum + getTotalTextLength(node),
|
|
60
|
-
0
|
|
61
|
-
);
|
|
62
|
-
case _snapssdk.NodeType.Row:
|
|
63
|
-
return getTotalTextLength(component.value);
|
|
64
|
-
case _snapssdk.NodeType.Text:
|
|
65
|
-
return component.value.length;
|
|
66
|
-
default:
|
|
67
|
-
return 0;
|
|
68
|
-
}
|
|
69
|
-
}
|
|
70
|
-
function hasChildren(component) {
|
|
71
|
-
return _utils.hasProperty.call(void 0, component, "children");
|
|
72
|
-
}
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
exports.validateTextLinks = validateTextLinks; exports.validateComponentLinks = validateComponentLinks; exports.getTotalTextLength = getTotalTextLength; exports.hasChildren = hasChildren;
|
|
80
|
-
//# sourceMappingURL=chunk-NDIITWO4.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/ui.ts"],"names":[],"mappings":";AACA,SAAS,gBAAgB;AACzB,SAAS,QAAQ,gBAAgB,mBAAmB;AAEpD,SAAS,OAAO,kBAAkB;AAElC,IAAM,oBAAoB,CAAC,UAAU,SAAS;AAQ9C,SAAS,iBAAiB,MAAc;AACtC,QAAM,SAAS,MAAM,MAAM,EAAE,KAAK,MAAM,CAAC;AACzC,QAAM,QAA0C,CAAC;AAGjD,aAAW,QAAQ,CAAC,UAAU;AAC5B,QAAI,MAAM,SAAS,QAAQ;AACzB,YAAM,KAAK,KAAK;AAAA,IAClB;AAAA,EACF,CAAC;AAED,SAAO,MAAM,IAAI,CAAC,SAAS,MAAM,IAAI,EAAE,OAAO,OAAO;AACvD;AAUO,SAAS,kBACd,MACA,kBACA;AACA,QAAM,QAAQ,iBAAiB,IAAI;AAEnC,aAAW,QAAQ,OAAO;AACxB,QAAI;AACF,YAAM,MAAM,IAAI,IAAI,IAAI;AACxB;AAAA,QACE,kBAAkB,SAAS,IAAI,QAAQ;AAAA,QACvC,4BAA4B,kBAAkB,KAAK,IAAI,CAAC;AAAA,MAC1D;AAEA,YAAM,WACJ,IAAI,aAAa,YAAY,IAAI,SAAS,MAAM,GAAG,EAAE,CAAC,IAAI,IAAI;AAEhE,aAAO,CAAC,iBAAiB,QAAQ,GAAG,mCAAmC;AAAA,IACzE,SAAS,OAAO;AACd,YAAM,IAAI;AAAA,QACR,gBACE,iBAAiB,iBACb,MAAM,UACN,sBACN;AAAA,MACF;AAAA,IACF;AAAA,EACF;AACF;AAWO,SAAS,uBACd,WACA,kBACA;AACA,QAAM,EAAE,KAAK,IAAI;AACjB,UAAQ,MAAM;AAAA,IACZ,KAAK,SAAS;AACZ,gBAAU,SAAS;AAAA,QAAQ,CAAC,SAC1B,uBAAuB,MAAM,gBAAgB;AAAA,MAC/C;AACA;AAAA,IACF,KAAK,SAAS;AACZ,6BAAuB,UAAU,OAAO,gBAAgB;AACxD;AAAA,IACF,KAAK,SAAS;AACZ,wBAAkB,UAAU,OAAO,gBAAgB;AACnD;AAAA,IACF;AACE;AAAA,EACJ;AACF;AAQO,SAAS,mBAAmB,WAA8B;AAC/D,QAAM,EAAE,KAAK,IAAI;AAEjB,UAAQ,MAAM;AAAA,IACZ,KAAK,SAAS;AACZ,aAAO,UAAU,SAAS;AAAA;AAAA;AAAA,QAGxB,CAAC,KAAK,SAAS,MAAM,mBAAmB,IAAI;AAAA,QAC5C;AAAA,MACF;AAAA,IACF,KAAK,SAAS;AACZ,aAAO,mBAAmB,UAAU,KAAK;AAAA,IAC3C,KAAK,SAAS;AACZ,aAAO,UAAU,MAAM;AAAA,IACzB;AACE,aAAO;AAAA,EACX;AACF;AAQO,SAAS,YACd,WAC+B;AAC/B,SAAO,YAAY,WAAW,UAAU;AAC1C","sourcesContent":["import type { Component, NodeWithChildren } from '@metamask/snaps-sdk';\nimport { NodeType } from '@metamask/snaps-sdk';\nimport { assert, AssertionError, hasProperty } from '@metamask/utils';\nimport type { Tokens } from 'marked';\nimport { lexer, walkTokens } from 'marked';\n\nconst ALLOWED_PROTOCOLS = ['https:', 'mailto:'];\n\n/**\n * Extract all links from a Markdown text string using the `marked` lexer.\n *\n * @param text - The markdown text string.\n * @returns A list of URLs linked to in the string.\n */\nfunction getMarkdownLinks(text: string) {\n const tokens = lexer(text, { gfm: false });\n const links: (Tokens.Link | Tokens.Generic)[] = [];\n\n // Walk the lexed tokens and collect all link tokens\n walkTokens(tokens, (token) => {\n if (token.type === 'link') {\n links.push(token);\n }\n });\n\n return links.map((link) => link?.href).filter(Boolean);\n}\n\n/**\n * Searches for markdown links in a string and checks them against the phishing list.\n *\n * @param text - The text to verify.\n * @param isOnPhishingList - The function that checks the link against the\n * phishing list.\n * @throws If the text contains a link that is not allowed.\n */\nexport function validateTextLinks(\n text: string,\n isOnPhishingList: (url: string) => boolean,\n) {\n const links = getMarkdownLinks(text);\n\n for (const link of links) {\n try {\n const url = new URL(link);\n assert(\n ALLOWED_PROTOCOLS.includes(url.protocol),\n `Protocol must be one of: ${ALLOWED_PROTOCOLS.join(', ')}.`,\n );\n\n const hostname =\n url.protocol === 'mailto:' ? url.pathname.split('@')[1] : url.hostname;\n\n assert(!isOnPhishingList(hostname), 'The specified URL is not allowed.');\n } catch (error) {\n throw new Error(\n `Invalid URL: ${\n error instanceof AssertionError\n ? error.message\n : 'Unable to parse URL.'\n }`,\n );\n }\n }\n}\n\n/**\n * Search for links in UI components and check that the URL they are trying to\n * pass in is not in the phishing list.\n *\n * @param component - The custom UI component.\n * @param isOnPhishingList - The function that checks the link against the\n * phishing list.\n * @throws If the component contains a link that is not allowed.\n */\nexport function validateComponentLinks(\n component: Component,\n isOnPhishingList: (url: string) => boolean,\n) {\n const { type } = component;\n switch (type) {\n case NodeType.Panel:\n component.children.forEach((node) =>\n validateComponentLinks(node, isOnPhishingList),\n );\n break;\n case NodeType.Row:\n validateComponentLinks(component.value, isOnPhishingList);\n break;\n case NodeType.Text:\n validateTextLinks(component.value, isOnPhishingList);\n break;\n default:\n break;\n }\n}\n\n/**\n * Calculate the total length of all text in the component.\n *\n * @param component - A custom UI component.\n * @returns The total length of all text components in the component.\n */\nexport function getTotalTextLength(component: Component): number {\n const { type } = component;\n\n switch (type) {\n case NodeType.Panel:\n return component.children.reduce<number>(\n // This is a bug in TypeScript: https://github.com/microsoft/TypeScript/issues/48313\n // eslint-disable-next-line @typescript-eslint/restrict-plus-operands\n (sum, node) => sum + getTotalTextLength(node),\n 0,\n );\n case NodeType.Row:\n return getTotalTextLength(component.value);\n case NodeType.Text:\n return component.value.length;\n default:\n return 0;\n }\n}\n\n/**\n * Check if a component has children.\n *\n * @param component - A custom UI component.\n * @returns `true` if the component has children, `false` otherwise.\n */\nexport function hasChildren(\n component: Component,\n): component is NodeWithChildren {\n return hasProperty(component, 'children');\n}\n"]}
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|