@chainpatrol/sdk 0.1.4 → 0.2.1
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/LICENSE +21 -0
- package/dist/index.d.ts +42 -0
- package/dist/index.js +12 -1
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +12 -1
- package/dist/index.mjs.map +1 -1
- package/package.json +11 -3
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2023 ChainPatrol Inc.
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/dist/index.d.ts
CHANGED
|
@@ -98,6 +98,48 @@ declare class ChainPatrolClient {
|
|
|
98
98
|
status: AssetStatus;
|
|
99
99
|
}[]>;
|
|
100
100
|
};
|
|
101
|
+
get report(): {
|
|
102
|
+
create: (req: {
|
|
103
|
+
/** Report title */
|
|
104
|
+
title: string;
|
|
105
|
+
/** Report description */
|
|
106
|
+
description: string;
|
|
107
|
+
/** List of assets to report with the proposed status */
|
|
108
|
+
assets: {
|
|
109
|
+
content: string;
|
|
110
|
+
status: AssetStatus;
|
|
111
|
+
}[];
|
|
112
|
+
/** Organization slug (provide this or `discordGuildId`) */
|
|
113
|
+
organizationSlug?: string;
|
|
114
|
+
/** Discord guild ID (provide this or `organizationSlug`) */
|
|
115
|
+
discordGuildId?: string;
|
|
116
|
+
/** Optional raw input of the assets */
|
|
117
|
+
rawAssetsInput?: string;
|
|
118
|
+
/** Optional List of URLs of images to attach to the report */
|
|
119
|
+
attachmentUrls?: string[];
|
|
120
|
+
/** Optional contact information of the reporter */
|
|
121
|
+
contactInfo?: string;
|
|
122
|
+
/** Optional ID of the reporter if they are a member on ChainPatrol */
|
|
123
|
+
reporterId?: number;
|
|
124
|
+
/**
|
|
125
|
+
* Optional information about the reporter if they are reporting from
|
|
126
|
+
* a platform other than ChainPatrol
|
|
127
|
+
*/
|
|
128
|
+
externalReporter?: {
|
|
129
|
+
platform: string;
|
|
130
|
+
platformIdentifier: string;
|
|
131
|
+
avatarUrl?: string;
|
|
132
|
+
};
|
|
133
|
+
}) => Promise<{
|
|
134
|
+
id: number;
|
|
135
|
+
createdAt: string;
|
|
136
|
+
organization: {
|
|
137
|
+
id: number;
|
|
138
|
+
slug: string;
|
|
139
|
+
name: string;
|
|
140
|
+
};
|
|
141
|
+
}>;
|
|
142
|
+
};
|
|
101
143
|
}
|
|
102
144
|
|
|
103
145
|
interface Storage {
|
package/dist/index.js
CHANGED
|
@@ -497,7 +497,18 @@ var ChainPatrolClient = class {
|
|
|
497
497
|
list: (req) => __async(this, null, function* () {
|
|
498
498
|
return yield this.fetch({
|
|
499
499
|
path: ["v2", "asset", "list"],
|
|
500
|
-
method: "
|
|
500
|
+
method: "POST",
|
|
501
|
+
body: req
|
|
502
|
+
});
|
|
503
|
+
})
|
|
504
|
+
};
|
|
505
|
+
}
|
|
506
|
+
get report() {
|
|
507
|
+
return {
|
|
508
|
+
create: (req) => __async(this, null, function* () {
|
|
509
|
+
return yield this.fetch({
|
|
510
|
+
path: ["v2", "report", "create"],
|
|
511
|
+
method: "POST",
|
|
501
512
|
body: req
|
|
502
513
|
});
|
|
503
514
|
})
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/events.ts","../src/logger.ts","../src/relay.ts","../src/detector.ts","../../../node_modules/normalize-url/index.js","../src/client.ts","../src/storage/index.ts","../src/storage/define-storage.ts","../src/storage/extension.ts","../src/storage/browser.ts","../src/storage/memory.ts"],"names":["LogLevel","list"],"mappings":"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","sourcesContent":["const ContinueAtOwnRisk = \"CHAINPATROL_CONTINUE_AT_OWN_RISK\";\nconst IgnorelistUpdated = \"CHAINPATROL_IGNORELIST_UPDATED\";\nconst CloseCurrentTab = \"CHAINPATROL_CLOSE_CURRENT_TAB\";\n\nexport const Events = {\n ContinueAtOwnRisk,\n IgnorelistUpdated,\n CloseCurrentTab,\n} as const;\n\nexport type EventData = {\n [ContinueAtOwnRisk]: {\n domain: string;\n };\n [IgnorelistUpdated]: {\n domain: string;\n };\n [CloseCurrentTab]: {};\n};\n","export enum LogLevel {\n DEBUG,\n INFO,\n WARN,\n ERROR,\n NONE,\n}\n\nexport class Logger {\n private meta: Record<string, unknown> = {};\n private minLevel: LogLevel;\n\n constructor(\n meta?: Record<string, unknown>,\n minLevel: LogLevel = LogLevel.NONE\n ) {\n if (meta) {\n this.meta = meta;\n }\n this.minLevel = minLevel;\n }\n\n public with(fields: Record<string, unknown>) {\n return new Logger({ ...this.meta, ...fields }, this.minLevel);\n }\n\n public debug(message: string, fields?: Record<string, unknown>) {\n this.log(LogLevel.DEBUG, message, fields);\n }\n\n public info(message: string, fields?: Record<string, unknown>) {\n this.log(LogLevel.INFO, message, fields);\n }\n\n public warn(message: string, fields?: Record<string, unknown>) {\n this.log(LogLevel.WARN, message, fields);\n }\n\n public error(message: string, fields?: Record<string, unknown>) {\n this.log(LogLevel.ERROR, message, fields);\n }\n\n private log(\n level: LogLevel,\n message: string,\n fields?: Record<string, unknown>\n ) {\n if (level < this.minLevel) {\n return; // Skip logging if log level is lower than minimum level\n }\n\n const logObj = { message, data: { ...fields }, ...this.meta };\n const logString = JSON.stringify(logObj, null, 2);\n console.log(`[${LogLevel[level].toUpperCase()}] ${logString}`);\n }\n}\n","import { EventData } from \"./events\";\nimport { Logger } from \"./logger\";\n\ntype Message<EventType extends keyof EventData> = {\n type: EventType;\n data: EventData[EventType];\n _meta: {\n id: string;\n origin: string;\n };\n};\n\nfunction getExtensionRuntime(): typeof chrome.runtime {\n if ((globalThis as any).browser?.runtime) {\n return (globalThis as any).browser.runtime;\n }\n if (globalThis.chrome?.runtime) {\n return globalThis.chrome.runtime;\n }\n throw new Error(\"No extension runtime found\");\n}\n\nfunction isExtensionHost() {\n return (\n !!(globalThis as any).browser?.runtime ||\n !!(globalThis as any).chrome?.runtime\n );\n}\n\nfunction isContentScript() {\n return isExtensionHost() && isBrowserHost();\n}\n\nfunction isBackgroundScript() {\n return isExtensionHost() && !isBrowserHost();\n}\n\nfunction isBrowserHost() {\n return !!(globalThis as any).window;\n}\n\ntype Handle = {\n addListener: (callback: (message: any) => void) => void;\n removeListener: (callback: (message: any) => void) => void;\n postMessage: (message: any) => void;\n};\n\nfunction getBackgroundScriptHandle(): Handle {\n const runtime = getExtensionRuntime();\n return {\n addListener: (callback: (message: any) => void) => {\n runtime.onMessage.addListener(callback);\n },\n removeListener: (callback: (message: any) => void) => {\n runtime.onMessage.removeListener(callback);\n },\n postMessage: async (message: any) => {\n const [tab] = await globalThis.chrome.tabs.query({\n active: true,\n lastFocusedWindow: true,\n });\n if (!tab.id || tab.id === globalThis.chrome.tabs.TAB_ID_NONE) {\n console.error(\"No active tab found\");\n return;\n }\n globalThis.chrome.tabs.sendMessage(tab.id, message);\n },\n };\n}\n\nfunction getContentScriptHandle(): Handle {\n const runtime = getExtensionRuntime();\n return {\n addListener: (callback: (message: any) => void) => {\n runtime.onMessage.addListener(callback);\n },\n removeListener: (callback: (message: any) => void) => {\n runtime.onMessage.removeListener(callback);\n },\n postMessage: async (message: any) => {\n runtime.sendMessage(message).catch((error) => {\n console.error(\"Failed to send message\", { message, error });\n });\n },\n };\n}\n\nfunction getBrowserHandle(): Handle {\n return {\n addListener: (callback: (message: any) => void) => {\n globalThis.window.addEventListener(\"message\", (event) => {\n if (event.source !== globalThis.window) {\n return;\n }\n callback(event.data);\n });\n },\n removeListener: (callback: (message: any) => void) => {\n globalThis.window.removeEventListener(\"message\", callback);\n },\n postMessage: (message: any) => {\n globalThis.window.postMessage(message, \"*\");\n },\n };\n}\n\n/**\n * Relay contains methods for implementing an event relay. It is used to\n * forward events between Javascript contexts:\n *\n * `<window>` <-> `<content script>` <-> `<background script>`\n *\n * Call `Relay.send` to send an event from one context to another. Call\n * `Relay.on` to listen for events in the current context. Call `Relay.run`\n * to start listening for events in the current context and forward them\n * to all other contexts.\n */\nexport class Relay {\n protected static handles: Handle[] = [];\n private static readonly logger = new Logger({ component: \"Relay\" });\n\n static {\n if (isBackgroundScript()) {\n Relay.logger.info(\"Detected background script\");\n Relay.handles.push(getBackgroundScriptHandle());\n } else if (isContentScript()) {\n Relay.logger.info(\"Detected content script\");\n Relay.handles.push(getContentScriptHandle());\n Relay.handles.push(getBrowserHandle());\n } else if (isBrowserHost()) {\n Relay.logger.info(\"Detected browser host\");\n Relay.handles.push(getBrowserHandle());\n }\n }\n\n public static send<EventType extends keyof EventData>(\n type: EventType,\n data: EventData[EventType]\n ) {\n const message = {\n type,\n data,\n _meta: {\n id: Math.random().toString(36).substring(2, 9),\n origin: globalThis.location.origin,\n },\n } satisfies Message<EventType>;\n\n Relay.logger.debug(\"Sending message\", message);\n\n for (const handle of Relay.handles) {\n handle.postMessage(message);\n }\n }\n\n public static run(events: (keyof EventData)[]) {\n const listeners = new Set<(message: any) => void>();\n\n for (const handle of Relay.handles) {\n const listener = Relay.handleMessage.bind(null, handle, events);\n listeners.add(listener);\n handle.addListener(listener);\n }\n\n Relay.logger.debug(\"Started relay\", { events });\n\n return () => {\n for (const handle of Relay.handles) {\n for (const listener of listeners) {\n handle.removeListener(listener);\n }\n }\n\n Relay.logger.debug(\"Stopped relay\", { events });\n };\n }\n\n private static handleMessage(\n sourceHandle: Handle,\n events: (keyof EventData)[],\n message: any\n ) {\n if (!events.includes(message.type)) {\n Relay.logger.debug(\"Ignoring message\", { message });\n return;\n }\n\n const destinationHandles = Relay.handles.filter(\n (handle) => handle !== sourceHandle\n );\n\n for (const destinationHandle of destinationHandles) {\n destinationHandle.postMessage(message);\n }\n }\n\n public static on<EventType extends keyof EventData>(\n targetEvent: EventType,\n callback: (data: EventData[EventType]) => void\n ) {\n const listeners = new Set<(message: any) => void>();\n for (const handle of Relay.handles) {\n const listener = (message: any) => {\n if (message.type !== targetEvent) {\n Relay.logger.debug(\"Ignoring message\", { message });\n return;\n }\n callback(message.data);\n };\n listeners.add(listener);\n handle.addListener(listener);\n }\n\n return () => {\n for (const handle of Relay.handles) {\n for (const listener of listeners) {\n handle.removeListener(listener);\n }\n }\n };\n }\n}\n","import { parse as parseDomain } from \"tldts\";\nimport normalizeUrl from \"normalize-url\";\nimport { z } from \"zod\";\n\nimport { AssetStatus, ChainPatrolClient } from \"./client\";\nimport { Memory } from \"./storage\";\nimport type { Storage } from \"./storage/types\";\nimport { Logger } from \"./logger\";\n\ntype Prettify<T> = T extends infer U ? (U extends string ? U : never) : never;\n\nexport type DetectorAssetStatus = Prettify<AssetStatus | \"IGNORED\">;\n\ntype Mode = \"cloud\" | \"local\";\n\n// Branded type for domain strings\ntype Domain = string & { __domain: never };\n\nexport type URLResult =\n | {\n ok: true;\n status: DetectorAssetStatus;\n url: string;\n redirectUrl?: string;\n }\n | {\n ok: false;\n url: string;\n error: string;\n };\n\nexport class DomainParseError extends Error {\n constructor(message: string) {\n super(message);\n this.name = \"DomainParseError\";\n }\n}\n\nexport class ThreatDetector {\n static StorageKeys = {\n ALLOWLIST: \"chainpatrol.allowed\",\n BLOCKLIST: \"chainpatrol.blocked\",\n IGNORELIST: \"chainpatrol.ignored\",\n };\n\n private static readonly CHAINPATROL_WARNING_URL =\n \"https://app.chainpatrol.io/warning\";\n private static readonly Schema = z.object({\n version: z.literal(1),\n data: z.object({\n domains: z.array(z.string()),\n }),\n });\n\n private mode: Mode;\n private client?: ChainPatrolClient;\n private storage: Storage;\n private redirectUrl?: string | ((url: string) => string);\n private readonly logger = new Logger({ component: \"ThreatDetector\" });\n\n constructor({\n mode,\n storage,\n redirectUrl,\n }: {\n mode: \"local\";\n storage?: Storage;\n redirectUrl?: string | ((url: string) => string);\n });\n\n constructor({\n mode,\n apiKey,\n storage,\n redirectUrl,\n }: {\n mode: \"cloud\";\n apiKey: string;\n storage?: Storage;\n redirectUrl?: string | ((url: string) => string);\n });\n\n constructor({\n mode,\n apiKey,\n proxyUrl,\n storage,\n redirectUrl,\n }: {\n mode: \"cloud\";\n apiKey: string;\n proxyUrl?: string;\n storage?: Storage;\n redirectUrl?: string | ((url: string) => string);\n });\n\n constructor({\n mode = \"cloud\",\n apiKey = \"\",\n storage = Memory(),\n proxyUrl,\n redirectUrl,\n }: {\n mode?: Mode;\n apiKey?: string;\n proxyUrl?: string;\n storage?: Storage;\n redirectUrl?: string | ((url: string) => string);\n }) {\n this.mode = mode;\n this.storage = storage;\n this.redirectUrl = redirectUrl ?? ThreatDetector.CHAINPATROL_WARNING_URL;\n if (mode === \"cloud\") {\n this.client = new ChainPatrolClient({\n apiKey: apiKey,\n baseUrl: proxyUrl,\n });\n }\n }\n\n public async url(url: string): Promise<URLResult> {\n this.logger.debug(\"Checking URL\", { url });\n\n let domains: Domain[];\n try {\n domains = this.generateDomains(url);\n } catch (e) {\n this.logger.error(\"Unable to parse domain\", { url, error: e });\n return {\n ok: false,\n url,\n error:\n e instanceof DomainParseError ? e.message : \"Unable to parse domain\",\n };\n }\n\n this.logger.debug(\"Generated domains\", { domains });\n\n let results = (\n await Promise.all(domains.map((domain) => this.urlHelper(domain, url)))\n ).filter(\n <T extends URLResult>(r: T): r is T extends { ok: true } ? T : never =>\n r.ok\n );\n\n if (results.length === 0) {\n return {\n ok: false,\n url,\n error: \"URL does not have a valid domain\",\n };\n }\n\n this.logger.debug(\"Results for domains\", { results });\n\n if (results.some((r) => r.status === \"IGNORED\")) {\n return {\n ok: true,\n status: \"IGNORED\",\n url,\n };\n }\n\n for (const result of results) {\n if (result.ok && result.status !== \"UNKNOWN\") {\n return result;\n }\n }\n\n return results[0];\n }\n\n private generateDomains(_url: string): Domain[] {\n const domain = this.parseDomainOrThrow(_url);\n\n const domains = [domain];\n\n const parsedDomain = parseDomain(domain);\n if (!parsedDomain.subdomain) {\n return domains;\n }\n\n const subdomainParts = parsedDomain.subdomain?.split(\".\") ?? [];\n\n for (let i = 0; i < subdomainParts.length; i++) {\n const subdomain = subdomainParts.slice(i).join(\".\");\n domains.unshift(`${subdomain}.${domain}` as Domain);\n }\n\n return domains;\n }\n\n private async urlHelper(domain: Domain, url: string): Promise<URLResult> {\n let status = await this.getStatusFromCache(domain);\n\n if (this.mode === \"cloud\" && this.client && status === \"UNKNOWN\") {\n try {\n const res = await this.client.asset.check({\n type: \"URL\",\n content: domain,\n });\n\n // Update cache storage\n this.logger.debug(\"Updating cache\", { domain, status: res.status });\n if (res.status === \"ALLOWED\") {\n this.addDomainToCache(domain, ThreatDetector.StorageKeys.ALLOWLIST);\n } else if (res.status === \"BLOCKED\") {\n this.addDomainToCache(domain, ThreatDetector.StorageKeys.BLOCKLIST);\n }\n\n status = res.status;\n } catch (e) {\n return {\n ok: false,\n url: domain,\n error: \"Unable to check URL\",\n };\n }\n }\n\n let redirectUrl: string | undefined;\n\n if (status === \"BLOCKED\") {\n if (typeof this.redirectUrl === \"function\") {\n redirectUrl = this.redirectUrl(url);\n } else if (typeof this.redirectUrl === \"string\") {\n const newUrl = new URL(this.redirectUrl);\n newUrl.searchParams.set(\"originUrl\", url);\n redirectUrl = newUrl.toString();\n }\n }\n\n return {\n ok: true,\n status,\n url: domain,\n redirectUrl,\n };\n }\n\n public async allow(\n url: string\n ): Promise<\n { ok: true; url: string } | { ok: false; url: string; error: string }\n > {\n try {\n const domain = this.parseDomainOrThrow(url);\n\n this.logger.debug(\"Allowing URL\", { url, domain });\n\n await this.invalidateDomainInCaches(domain);\n await this.addDomainToCache(domain, ThreatDetector.StorageKeys.ALLOWLIST);\n\n return {\n ok: true,\n url: domain,\n };\n } catch (e) {\n this.logger.error(\"Unable to allow URL\", { url, error: e });\n return {\n ok: false,\n url,\n error: \"Unable to allow URL\",\n };\n }\n }\n\n public async block(\n url: string\n ): Promise<\n { ok: true; url: string } | { ok: false; url: string; error: string }\n > {\n try {\n const domain = this.parseDomainOrThrow(url);\n\n this.logger.debug(\"Blocking URL\", { url, domain });\n\n await this.invalidateDomainInCaches(domain);\n await this.addDomainToCache(domain, ThreatDetector.StorageKeys.BLOCKLIST);\n\n return {\n ok: true,\n url: domain,\n };\n } catch (e) {\n this.logger.error(\"Unable to block URL\", { url, error: e });\n return {\n ok: false,\n url,\n error: \"Unable to block URL\",\n };\n }\n }\n\n public async ignore(\n url: string\n ): Promise<\n { ok: true; url: string } | { ok: false; url: string; error: string }\n > {\n try {\n const domain = this.parseDomainOrThrow(url);\n\n this.logger.debug(\"Ignoring URL\", { url, domain });\n\n await this.addDomainToCache(\n domain,\n ThreatDetector.StorageKeys.IGNORELIST\n );\n\n return {\n ok: true,\n url: domain,\n };\n } catch (e) {\n this.logger.error(\"Unable to ignore URL\", { url, error: e });\n return {\n ok: false,\n url,\n error: \"Unable to ignore URL\",\n };\n }\n }\n\n private parseDomainOrThrow(url: string): Domain {\n this.logger.debug(\"Parsing domain\", { url });\n try {\n const normalizedUrl = normalizeUrl(url, {\n stripWWW: false,\n removeTrailingSlash: false,\n });\n\n this.logger.debug(\"Normalized URL\", { from: url, to: normalizedUrl });\n\n const parsedURL = new URL(normalizedUrl);\n\n this.logger.debug(\"Extract domain from URL\", { url: parsedURL.hostname });\n\n const parsedSubdomainResult = parseDomain(parsedURL.hostname);\n\n this.logger.debug(\"Parsed domain\", { parsedSubdomainResult });\n\n if (parsedSubdomainResult.hostname === \"localhost\") {\n throw new DomainParseError(\"ThreatDetector does not support localhost\");\n }\n\n if (parsedSubdomainResult.isIp) {\n throw new DomainParseError(\n \"ThreatDetector does not support IP addresses\"\n );\n }\n\n if (!parsedSubdomainResult.domain) {\n throw new DomainParseError(\"Unable to parse domain\");\n }\n\n const domain = parsedSubdomainResult.domain as Domain;\n\n return domain;\n } catch (e) {\n if (e instanceof DomainParseError) {\n throw e;\n } else {\n this.logger.error(\"Unable to parse domain\", { url, error: e });\n throw new DomainParseError(\"Unable to parse domain\");\n }\n }\n }\n\n private async invalidateDomainInCaches(domain: Domain): Promise<void> {\n await this.invalidateDomainInCache(\n domain,\n ThreatDetector.StorageKeys.ALLOWLIST\n );\n await this.invalidateDomainInCache(\n domain,\n ThreatDetector.StorageKeys.BLOCKLIST\n );\n }\n\n private async invalidateDomainInCache(\n domain: Domain,\n key: string\n ): Promise<void> {\n const data = await this.storage.get(key);\n\n if (!data) {\n return;\n }\n\n const list = await this.getListFromStorage(key);\n\n if (!list.data.domains.includes(domain)) {\n return;\n }\n\n list.data.domains = list.data.domains.filter((u) => u !== domain);\n\n await this.setListInStorage(key, list);\n }\n\n private async addDomainToCache(domain: Domain, key: string): Promise<void> {\n const list = await this.getListFromStorage(key);\n\n if (list.data.domains.includes(domain)) {\n return;\n }\n\n list.data.domains.push(domain);\n\n await this.setListInStorage(key, list);\n }\n\n private async isDomainInList(domain: Domain, key: string): Promise<boolean> {\n const list = await this.getListFromStorage(key);\n return list.data.domains.includes(domain);\n }\n\n private async getListFromStorage(\n key: string\n ): Promise<z.infer<typeof ThreatDetector.Schema>> {\n const data = await this.storage.get(key);\n\n if (!data) {\n const list: z.infer<typeof ThreatDetector.Schema> = {\n version: 1,\n data: {\n domains: [],\n },\n };\n await this.setListInStorage(key, list);\n return list;\n }\n\n const list = ThreatDetector.Schema.parse(JSON.parse(data));\n\n return list;\n }\n\n private async setListInStorage(\n key: string,\n list: z.infer<typeof ThreatDetector.Schema>\n ): Promise<void> {\n await this.storage.set(key, JSON.stringify(list));\n }\n\n private async getStatusFromCache(\n domain: Domain\n ): Promise<DetectorAssetStatus> {\n if (\n await this.isDomainInList(domain, ThreatDetector.StorageKeys.IGNORELIST)\n ) {\n return \"IGNORED\";\n } else if (\n await this.isDomainInList(domain, ThreatDetector.StorageKeys.BLOCKLIST)\n ) {\n return \"BLOCKED\";\n } else if (\n await this.isDomainInList(domain, ThreatDetector.StorageKeys.ALLOWLIST)\n ) {\n return \"ALLOWED\";\n } else {\n return \"UNKNOWN\";\n }\n }\n}\n","// https://developer.mozilla.org/en-US/docs/Web/HTTP/Basics_of_HTTP/Data_URIs\nconst DATA_URL_DEFAULT_MIME_TYPE = 'text/plain';\nconst DATA_URL_DEFAULT_CHARSET = 'us-ascii';\n\nconst testParameter = (name, filters) => filters.some(filter => filter instanceof RegExp ? filter.test(name) : filter === name);\n\nconst supportedProtocols = new Set([\n\t'https:',\n\t'http:',\n\t'file:',\n]);\n\nconst hasCustomProtocol = urlString => {\n\ttry {\n\t\tconst {protocol} = new URL(urlString);\n\t\treturn protocol.endsWith(':') && !supportedProtocols.has(protocol);\n\t} catch {\n\t\treturn false;\n\t}\n};\n\nconst normalizeDataURL = (urlString, {stripHash}) => {\n\tconst match = /^data:(?<type>[^,]*?),(?<data>[^#]*?)(?:#(?<hash>.*))?$/.exec(urlString);\n\n\tif (!match) {\n\t\tthrow new Error(`Invalid URL: ${urlString}`);\n\t}\n\n\tlet {type, data, hash} = match.groups;\n\tconst mediaType = type.split(';');\n\thash = stripHash ? '' : hash;\n\n\tlet isBase64 = false;\n\tif (mediaType[mediaType.length - 1] === 'base64') {\n\t\tmediaType.pop();\n\t\tisBase64 = true;\n\t}\n\n\t// Lowercase MIME type\n\tconst mimeType = mediaType.shift()?.toLowerCase() ?? '';\n\tconst attributes = mediaType\n\t\t.map(attribute => {\n\t\t\tlet [key, value = ''] = attribute.split('=').map(string => string.trim());\n\n\t\t\t// Lowercase `charset`\n\t\t\tif (key === 'charset') {\n\t\t\t\tvalue = value.toLowerCase();\n\n\t\t\t\tif (value === DATA_URL_DEFAULT_CHARSET) {\n\t\t\t\t\treturn '';\n\t\t\t\t}\n\t\t\t}\n\n\t\t\treturn `${key}${value ? `=${value}` : ''}`;\n\t\t})\n\t\t.filter(Boolean);\n\n\tconst normalizedMediaType = [\n\t\t...attributes,\n\t];\n\n\tif (isBase64) {\n\t\tnormalizedMediaType.push('base64');\n\t}\n\n\tif (normalizedMediaType.length > 0 || (mimeType && mimeType !== DATA_URL_DEFAULT_MIME_TYPE)) {\n\t\tnormalizedMediaType.unshift(mimeType);\n\t}\n\n\treturn `data:${normalizedMediaType.join(';')},${isBase64 ? data.trim() : data}${hash ? `#${hash}` : ''}`;\n};\n\nexport default function normalizeUrl(urlString, options) {\n\toptions = {\n\t\tdefaultProtocol: 'http',\n\t\tnormalizeProtocol: true,\n\t\tforceHttp: false,\n\t\tforceHttps: false,\n\t\tstripAuthentication: true,\n\t\tstripHash: false,\n\t\tstripTextFragment: true,\n\t\tstripWWW: true,\n\t\tremoveQueryParameters: [/^utm_\\w+/i],\n\t\tremoveTrailingSlash: true,\n\t\tremoveSingleSlash: true,\n\t\tremoveDirectoryIndex: false,\n\t\tremoveExplicitPort: false,\n\t\tsortQueryParameters: true,\n\t\t...options,\n\t};\n\n\t// Legacy: Append `:` to the protocol if missing.\n\tif (typeof options.defaultProtocol === 'string' && !options.defaultProtocol.endsWith(':')) {\n\t\toptions.defaultProtocol = `${options.defaultProtocol}:`;\n\t}\n\n\turlString = urlString.trim();\n\n\t// Data URL\n\tif (/^data:/i.test(urlString)) {\n\t\treturn normalizeDataURL(urlString, options);\n\t}\n\n\tif (hasCustomProtocol(urlString)) {\n\t\treturn urlString;\n\t}\n\n\tconst hasRelativeProtocol = urlString.startsWith('//');\n\tconst isRelativeUrl = !hasRelativeProtocol && /^\\.*\\//.test(urlString);\n\n\t// Prepend protocol\n\tif (!isRelativeUrl) {\n\t\turlString = urlString.replace(/^(?!(?:\\w+:)?\\/\\/)|^\\/\\//, options.defaultProtocol);\n\t}\n\n\tconst urlObject = new URL(urlString);\n\n\tif (options.forceHttp && options.forceHttps) {\n\t\tthrow new Error('The `forceHttp` and `forceHttps` options cannot be used together');\n\t}\n\n\tif (options.forceHttp && urlObject.protocol === 'https:') {\n\t\turlObject.protocol = 'http:';\n\t}\n\n\tif (options.forceHttps && urlObject.protocol === 'http:') {\n\t\turlObject.protocol = 'https:';\n\t}\n\n\t// Remove auth\n\tif (options.stripAuthentication) {\n\t\turlObject.username = '';\n\t\turlObject.password = '';\n\t}\n\n\t// Remove hash\n\tif (options.stripHash) {\n\t\turlObject.hash = '';\n\t} else if (options.stripTextFragment) {\n\t\turlObject.hash = urlObject.hash.replace(/#?:~:text.*?$/i, '');\n\t}\n\n\t// Remove duplicate slashes if not preceded by a protocol\n\t// NOTE: This could be implemented using a single negative lookbehind\n\t// regex, but we avoid that to maintain compatibility with older js engines\n\t// which do not have support for that feature.\n\tif (urlObject.pathname) {\n\t\t// TODO: Replace everything below with `urlObject.pathname = urlObject.pathname.replace(/(?<!\\b[a-z][a-z\\d+\\-.]{1,50}:)\\/{2,}/g, '/');` when Safari supports negative lookbehind.\n\n\t\t// Split the string by occurrences of this protocol regex, and perform\n\t\t// duplicate-slash replacement on the strings between those occurrences\n\t\t// (if any).\n\t\tconst protocolRegex = /\\b[a-z][a-z\\d+\\-.]{1,50}:\\/\\//g;\n\n\t\tlet lastIndex = 0;\n\t\tlet result = '';\n\t\tfor (;;) {\n\t\t\tconst match = protocolRegex.exec(urlObject.pathname);\n\t\t\tif (!match) {\n\t\t\t\tbreak;\n\t\t\t}\n\n\t\t\tconst protocol = match[0];\n\t\t\tconst protocolAtIndex = match.index;\n\t\t\tconst intermediate = urlObject.pathname.slice(lastIndex, protocolAtIndex);\n\n\t\t\tresult += intermediate.replace(/\\/{2,}/g, '/');\n\t\t\tresult += protocol;\n\t\t\tlastIndex = protocolAtIndex + protocol.length;\n\t\t}\n\n\t\tconst remnant = urlObject.pathname.slice(lastIndex, urlObject.pathname.length);\n\t\tresult += remnant.replace(/\\/{2,}/g, '/');\n\n\t\turlObject.pathname = result;\n\t}\n\n\t// Decode URI octets\n\tif (urlObject.pathname) {\n\t\ttry {\n\t\t\turlObject.pathname = decodeURI(urlObject.pathname);\n\t\t} catch {}\n\t}\n\n\t// Remove directory index\n\tif (options.removeDirectoryIndex === true) {\n\t\toptions.removeDirectoryIndex = [/^index\\.[a-z]+$/];\n\t}\n\n\tif (Array.isArray(options.removeDirectoryIndex) && options.removeDirectoryIndex.length > 0) {\n\t\tlet pathComponents = urlObject.pathname.split('/');\n\t\tconst lastComponent = pathComponents[pathComponents.length - 1];\n\n\t\tif (testParameter(lastComponent, options.removeDirectoryIndex)) {\n\t\t\tpathComponents = pathComponents.slice(0, -1);\n\t\t\turlObject.pathname = pathComponents.slice(1).join('/') + '/';\n\t\t}\n\t}\n\n\tif (urlObject.hostname) {\n\t\t// Remove trailing dot\n\t\turlObject.hostname = urlObject.hostname.replace(/\\.$/, '');\n\n\t\t// Remove `www.`\n\t\tif (options.stripWWW && /^www\\.(?!www\\.)[a-z\\-\\d]{1,63}\\.[a-z.\\-\\d]{2,63}$/.test(urlObject.hostname)) {\n\t\t\t// Each label should be max 63 at length (min: 1).\n\t\t\t// Source: https://en.wikipedia.org/wiki/Hostname#Restrictions_on_valid_host_names\n\t\t\t// Each TLD should be up to 63 characters long (min: 2).\n\t\t\t// It is technically possible to have a single character TLD, but none currently exist.\n\t\t\turlObject.hostname = urlObject.hostname.replace(/^www\\./, '');\n\t\t}\n\t}\n\n\t// Remove query unwanted parameters\n\tif (Array.isArray(options.removeQueryParameters)) {\n\t\t// eslint-disable-next-line unicorn/no-useless-spread -- We are intentionally spreading to get a copy.\n\t\tfor (const key of [...urlObject.searchParams.keys()]) {\n\t\t\tif (testParameter(key, options.removeQueryParameters)) {\n\t\t\t\turlObject.searchParams.delete(key);\n\t\t\t}\n\t\t}\n\t}\n\n\tif (!Array.isArray(options.keepQueryParameters) && options.removeQueryParameters === true) {\n\t\turlObject.search = '';\n\t}\n\n\t// Keep wanted query parameters\n\tif (Array.isArray(options.keepQueryParameters) && options.keepQueryParameters.length > 0) {\n\t\t// eslint-disable-next-line unicorn/no-useless-spread -- We are intentionally spreading to get a copy.\n\t\tfor (const key of [...urlObject.searchParams.keys()]) {\n\t\t\tif (!testParameter(key, options.keepQueryParameters)) {\n\t\t\t\turlObject.searchParams.delete(key);\n\t\t\t}\n\t\t}\n\t}\n\n\t// Sort query parameters\n\tif (options.sortQueryParameters) {\n\t\turlObject.searchParams.sort();\n\n\t\t// Calling `.sort()` encodes the search parameters, so we need to decode them again.\n\t\ttry {\n\t\t\turlObject.search = decodeURIComponent(urlObject.search);\n\t\t} catch {}\n\t}\n\n\tif (options.removeTrailingSlash) {\n\t\turlObject.pathname = urlObject.pathname.replace(/\\/$/, '');\n\t}\n\n\t// Remove an explicit port number, excluding a default port number, if applicable\n\tif (options.removeExplicitPort && urlObject.port) {\n\t\turlObject.port = '';\n\t}\n\n\tconst oldUrlString = urlString;\n\n\t// Take advantage of many of the Node `url` normalizations\n\turlString = urlObject.toString();\n\n\tif (!options.removeSingleSlash && urlObject.pathname === '/' && !oldUrlString.endsWith('/') && urlObject.hash === '') {\n\t\turlString = urlString.replace(/\\/$/, '');\n\t}\n\n\t// Remove ending `/` unless removeSingleSlash is false\n\tif ((options.removeTrailingSlash || urlObject.pathname === '/') && urlObject.hash === '' && options.removeSingleSlash) {\n\t\turlString = urlString.replace(/\\/$/, '');\n\t}\n\n\t// Restore relative protocol, if applicable\n\tif (hasRelativeProtocol && !options.normalizeProtocol) {\n\t\turlString = urlString.replace(/^http:\\/\\//, '//');\n\t}\n\n\t// Remove http/https\n\tif (options.stripProtocol) {\n\t\turlString = urlString.replace(/^(?:https?:)?\\/\\//, '');\n\t}\n\n\treturn urlString;\n}\n","import { Logger } from \"./logger\";\n\nexport type ChainPatrolClientOptions = {\n apiKey: string;\n baseUrl?: string;\n};\n\ntype ApiRequest = {\n path: string[];\n method: \"GET\" | \"POST\" | \"PUT\" | \"DELETE\";\n body?: unknown;\n};\n\nexport type AssetType = \"URL\" | \"PAGE\" | \"ADDRESS\";\nexport type AssetStatus = \"ALLOWED\" | \"BLOCKED\" | \"UNKNOWN\";\n\nfunction trimTrailingSlashes(url: string): string {\n return url.replace(/\\/+$/, \"\");\n}\n\nexport class ChainPatrolClient {\n public readonly baseUrl: string;\n private readonly apiKey: string;\n private readonly logger = new Logger({ component: \"ChainPatrolClient\" });\n\n constructor(options: ChainPatrolClientOptions) {\n this.baseUrl = options.baseUrl ?? \"https://app.chainpatrol.io/api/\";\n if (!options.apiKey) {\n throw new Error(\"ChainPatrol API key is required\");\n }\n this.apiKey = options.apiKey;\n }\n\n private async fetch<TResult = unknown>(req: ApiRequest): Promise<TResult> {\n const url = `${trimTrailingSlashes(this.baseUrl)}/${req.path.join(\"/\")}`;\n this.logger.debug(\"fetch\", { url, req });\n const res = await fetch(url, {\n method: req.method,\n headers: {\n \"Content-Type\": \"application/json\",\n \"X-Api-Key\": this.apiKey,\n },\n body: JSON.stringify(req.body),\n });\n if (!res.ok) {\n throw new Error(await res.text());\n }\n return res.json();\n }\n\n public get asset() {\n return {\n check: async (req: {\n type: AssetType;\n content: string;\n }): Promise<{\n /**\n * \"ALLOWED\" - the asset is on the allowlist\n * \"BLOCKED\" - the asset is on the blocklist\n * \"UNKNOWN\" - the asset's status is not known\n */\n status: AssetStatus;\n /**\n * If the asset is allowed or blocked, this will be the reason why.\n * ChainPatrol aggregates data from multiple sources, so this will\n * tell you which source blocked or allowed the asset.\n *\n * ex. 'eth-phishing-detect' - the asset is on MetaMask's blocklist\n * 'reported' - the asset is on ChainPatrol's blocklist because\n * it was reported by a user\n */\n reason?: string;\n }> => {\n return await this.fetch<{\n status: AssetStatus;\n reason?: string;\n }>({\n path: [\"v2\", \"asset\", \"check\"],\n method: \"POST\",\n body: req,\n });\n },\n\n list: async (req: {\n /**\n * Asset type\n */\n type: AssetType;\n /**\n * Status of the assets to retrieve\n */\n status: AssetStatus;\n /**\n * The start date to list assets from. This should be in the format `YYYY-MM-DD` and is inclusive.\n */\n startDate?: string;\n /**\n * The end date to list assets from. This should be in the format `YYYY-MM-DD` and is inclusive.\n */\n endDate?: string;\n }): Promise<\n {\n content: string;\n type: AssetType;\n status: AssetStatus;\n }[]\n > => {\n return await this.fetch<\n {\n content: string;\n type: AssetType;\n status: AssetStatus;\n }[]\n >({\n path: [\"v2\", \"asset\", \"list\"],\n method: \"GET\",\n body: req,\n });\n },\n };\n }\n}\n","export * from \"./extension\";\nexport * from \"./browser\";\nexport * from \"./memory\";\nexport { defineStorage } from \"./define-storage\";\nexport * from \"./types\";\n","import { ThreatDetector } from \"../detector\";\nimport { Storage } from \"./types\";\n\nexport interface Context {\n keys: string[];\n}\n\nexport function defineStorage<T extends Storage>(\n config: (ctx: Context) => T\n): () => T {\n return () =>\n config({\n keys: Object.values(ThreatDetector.StorageKeys),\n });\n}\n","import { defineStorage } from \"./define-storage\";\n\nexport const Extension = defineStorage(({ keys }) => {\n return {\n get: async (key: string) => {\n const result = await chrome.storage.local.get(key);\n return result[key];\n },\n set: async (key: string, value: string) => {\n await chrome.storage.local.set({ [key]: value });\n },\n delete: async (key: string) => {\n await chrome.storage.local.remove(key);\n },\n size: async () => {\n const usageBytes = await chrome.storage.local.getBytesInUse(keys);\n return usageBytes;\n },\n };\n});\n","import { defineStorage } from \"./define-storage\";\n\nfunction isStorageAvailable(type: \"localStorage\" | \"sessionStorage\") {\n let storage;\n try {\n storage = window[type];\n const x = \"__storage_test__\";\n storage.setItem(x, x);\n storage.removeItem(x);\n return true;\n } catch (e) {\n return (\n e instanceof DOMException &&\n // everything except Firefox\n (e.code === 22 ||\n // Firefox\n e.code === 1014 ||\n // test name field too, because code might not be present\n // everything except Firefox\n e.name === \"QuotaExceededError\" ||\n // Firefox\n e.name === \"NS_ERROR_DOM_QUOTA_REACHED\") &&\n // acknowledge QuotaExceededError only if there's something already stored\n storage &&\n storage.length !== 0\n );\n }\n}\n\nexport const Browser = defineStorage(({ keys }) => {\n if (!isStorageAvailable(\"localStorage\")) {\n throw new Error(\"localStorage is not available\");\n }\n\n return {\n get: async (key: string) => {\n return localStorage.getItem(key);\n },\n set: async (key: string, value: string) => {\n localStorage.setItem(key, value);\n },\n delete: async (key: string) => {\n localStorage.removeItem(key);\n },\n size: async () => {\n let total = 0;\n for (let i = 0; i < localStorage.length; i++) {\n const key = localStorage.key(i);\n if (key && keys.includes(key)) {\n total += localStorage.getItem(key)?.length ?? 0;\n }\n }\n return total;\n },\n };\n});\n","import { defineStorage } from \"./define-storage\";\n\nexport const Memory = defineStorage(() => {\n const storage = new Map<string, string>();\n return {\n get: async (key: string) => {\n return storage.get(key) || null;\n },\n set: async (key: string, value: string) => {\n storage.set(key, value);\n },\n delete: async (key: string) => {\n storage.delete(key);\n },\n size: async () => {\n let total = 0;\n for (const value of storage.values()) {\n total += value.length;\n }\n return total;\n },\n };\n});\n"]}
|
|
1
|
+
{"version":3,"sources":["../src/events.ts","../src/logger.ts","../src/relay.ts","../src/detector.ts","../../../node_modules/normalize-url/index.js","../src/client.ts","../src/storage/index.ts","../src/storage/define-storage.ts","../src/storage/extension.ts","../src/storage/browser.ts","../src/storage/memory.ts"],"names":["LogLevel","list"],"mappings":"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","sourcesContent":["const ContinueAtOwnRisk = \"CHAINPATROL_CONTINUE_AT_OWN_RISK\";\nconst IgnorelistUpdated = \"CHAINPATROL_IGNORELIST_UPDATED\";\nconst CloseCurrentTab = \"CHAINPATROL_CLOSE_CURRENT_TAB\";\n\nexport const Events = {\n ContinueAtOwnRisk,\n IgnorelistUpdated,\n CloseCurrentTab,\n} as const;\n\nexport type EventData = {\n [ContinueAtOwnRisk]: {\n domain: string;\n };\n [IgnorelistUpdated]: {\n domain: string;\n };\n [CloseCurrentTab]: {};\n};\n","export enum LogLevel {\n DEBUG,\n INFO,\n WARN,\n ERROR,\n NONE,\n}\n\nexport class Logger {\n private meta: Record<string, unknown> = {};\n private minLevel: LogLevel;\n\n constructor(\n meta?: Record<string, unknown>,\n minLevel: LogLevel = LogLevel.NONE\n ) {\n if (meta) {\n this.meta = meta;\n }\n this.minLevel = minLevel;\n }\n\n public with(fields: Record<string, unknown>) {\n return new Logger({ ...this.meta, ...fields }, this.minLevel);\n }\n\n public debug(message: string, fields?: Record<string, unknown>) {\n this.log(LogLevel.DEBUG, message, fields);\n }\n\n public info(message: string, fields?: Record<string, unknown>) {\n this.log(LogLevel.INFO, message, fields);\n }\n\n public warn(message: string, fields?: Record<string, unknown>) {\n this.log(LogLevel.WARN, message, fields);\n }\n\n public error(message: string, fields?: Record<string, unknown>) {\n this.log(LogLevel.ERROR, message, fields);\n }\n\n private log(\n level: LogLevel,\n message: string,\n fields?: Record<string, unknown>\n ) {\n if (level < this.minLevel) {\n return; // Skip logging if log level is lower than minimum level\n }\n\n const logObj = { message, data: { ...fields }, ...this.meta };\n const logString = JSON.stringify(logObj, null, 2);\n console.log(`[${LogLevel[level].toUpperCase()}] ${logString}`);\n }\n}\n","import { EventData } from \"./events\";\nimport { Logger } from \"./logger\";\n\ntype Message<EventType extends keyof EventData> = {\n type: EventType;\n data: EventData[EventType];\n _meta: {\n id: string;\n origin: string;\n };\n};\n\nfunction getExtensionRuntime(): typeof chrome.runtime {\n if ((globalThis as any).browser?.runtime) {\n return (globalThis as any).browser.runtime;\n }\n if (globalThis.chrome?.runtime) {\n return globalThis.chrome.runtime;\n }\n throw new Error(\"No extension runtime found\");\n}\n\nfunction isExtensionHost() {\n return (\n !!(globalThis as any).browser?.runtime ||\n !!(globalThis as any).chrome?.runtime\n );\n}\n\nfunction isContentScript() {\n return isExtensionHost() && isBrowserHost();\n}\n\nfunction isBackgroundScript() {\n return isExtensionHost() && !isBrowserHost();\n}\n\nfunction isBrowserHost() {\n return !!(globalThis as any).window;\n}\n\ntype Handle = {\n addListener: (callback: (message: any) => void) => void;\n removeListener: (callback: (message: any) => void) => void;\n postMessage: (message: any) => void;\n};\n\nfunction getBackgroundScriptHandle(): Handle {\n const runtime = getExtensionRuntime();\n return {\n addListener: (callback: (message: any) => void) => {\n runtime.onMessage.addListener(callback);\n },\n removeListener: (callback: (message: any) => void) => {\n runtime.onMessage.removeListener(callback);\n },\n postMessage: async (message: any) => {\n const [tab] = await globalThis.chrome.tabs.query({\n active: true,\n lastFocusedWindow: true,\n });\n if (!tab.id || tab.id === globalThis.chrome.tabs.TAB_ID_NONE) {\n console.error(\"No active tab found\");\n return;\n }\n globalThis.chrome.tabs.sendMessage(tab.id, message);\n },\n };\n}\n\nfunction getContentScriptHandle(): Handle {\n const runtime = getExtensionRuntime();\n return {\n addListener: (callback: (message: any) => void) => {\n runtime.onMessage.addListener(callback);\n },\n removeListener: (callback: (message: any) => void) => {\n runtime.onMessage.removeListener(callback);\n },\n postMessage: async (message: any) => {\n runtime.sendMessage(message).catch((error) => {\n console.error(\"Failed to send message\", { message, error });\n });\n },\n };\n}\n\nfunction getBrowserHandle(): Handle {\n return {\n addListener: (callback: (message: any) => void) => {\n globalThis.window.addEventListener(\"message\", (event) => {\n if (event.source !== globalThis.window) {\n return;\n }\n callback(event.data);\n });\n },\n removeListener: (callback: (message: any) => void) => {\n globalThis.window.removeEventListener(\"message\", callback);\n },\n postMessage: (message: any) => {\n globalThis.window.postMessage(message, \"*\");\n },\n };\n}\n\n/**\n * Relay contains methods for implementing an event relay. It is used to\n * forward events between Javascript contexts:\n *\n * `<window>` <-> `<content script>` <-> `<background script>`\n *\n * Call `Relay.send` to send an event from one context to another. Call\n * `Relay.on` to listen for events in the current context. Call `Relay.run`\n * to start listening for events in the current context and forward them\n * to all other contexts.\n */\nexport class Relay {\n protected static handles: Handle[] = [];\n private static readonly logger = new Logger({ component: \"Relay\" });\n\n static {\n if (isBackgroundScript()) {\n Relay.logger.info(\"Detected background script\");\n Relay.handles.push(getBackgroundScriptHandle());\n } else if (isContentScript()) {\n Relay.logger.info(\"Detected content script\");\n Relay.handles.push(getContentScriptHandle());\n Relay.handles.push(getBrowserHandle());\n } else if (isBrowserHost()) {\n Relay.logger.info(\"Detected browser host\");\n Relay.handles.push(getBrowserHandle());\n }\n }\n\n public static send<EventType extends keyof EventData>(\n type: EventType,\n data: EventData[EventType]\n ) {\n const message = {\n type,\n data,\n _meta: {\n id: Math.random().toString(36).substring(2, 9),\n origin: globalThis.location.origin,\n },\n } satisfies Message<EventType>;\n\n Relay.logger.debug(\"Sending message\", message);\n\n for (const handle of Relay.handles) {\n handle.postMessage(message);\n }\n }\n\n public static run(events: (keyof EventData)[]) {\n const listeners = new Set<(message: any) => void>();\n\n for (const handle of Relay.handles) {\n const listener = Relay.handleMessage.bind(null, handle, events);\n listeners.add(listener);\n handle.addListener(listener);\n }\n\n Relay.logger.debug(\"Started relay\", { events });\n\n return () => {\n for (const handle of Relay.handles) {\n for (const listener of listeners) {\n handle.removeListener(listener);\n }\n }\n\n Relay.logger.debug(\"Stopped relay\", { events });\n };\n }\n\n private static handleMessage(\n sourceHandle: Handle,\n events: (keyof EventData)[],\n message: any\n ) {\n if (!events.includes(message.type)) {\n Relay.logger.debug(\"Ignoring message\", { message });\n return;\n }\n\n const destinationHandles = Relay.handles.filter(\n (handle) => handle !== sourceHandle\n );\n\n for (const destinationHandle of destinationHandles) {\n destinationHandle.postMessage(message);\n }\n }\n\n public static on<EventType extends keyof EventData>(\n targetEvent: EventType,\n callback: (data: EventData[EventType]) => void\n ) {\n const listeners = new Set<(message: any) => void>();\n for (const handle of Relay.handles) {\n const listener = (message: any) => {\n if (message.type !== targetEvent) {\n Relay.logger.debug(\"Ignoring message\", { message });\n return;\n }\n callback(message.data);\n };\n listeners.add(listener);\n handle.addListener(listener);\n }\n\n return () => {\n for (const handle of Relay.handles) {\n for (const listener of listeners) {\n handle.removeListener(listener);\n }\n }\n };\n }\n}\n","import { parse as parseDomain } from \"tldts\";\nimport normalizeUrl from \"normalize-url\";\nimport { z } from \"zod\";\n\nimport { AssetStatus, ChainPatrolClient } from \"./client\";\nimport { Memory } from \"./storage\";\nimport type { Storage } from \"./storage/types\";\nimport { Logger } from \"./logger\";\n\ntype Prettify<T> = T extends infer U ? (U extends string ? U : never) : never;\n\nexport type DetectorAssetStatus = Prettify<AssetStatus | \"IGNORED\">;\n\ntype Mode = \"cloud\" | \"local\";\n\n// Branded type for domain strings\ntype Domain = string & { __domain: never };\n\nexport type URLResult =\n | {\n ok: true;\n status: DetectorAssetStatus;\n url: string;\n redirectUrl?: string;\n }\n | {\n ok: false;\n url: string;\n error: string;\n };\n\nexport class DomainParseError extends Error {\n constructor(message: string) {\n super(message);\n this.name = \"DomainParseError\";\n }\n}\n\nexport class ThreatDetector {\n static StorageKeys = {\n ALLOWLIST: \"chainpatrol.allowed\",\n BLOCKLIST: \"chainpatrol.blocked\",\n IGNORELIST: \"chainpatrol.ignored\",\n };\n\n private static readonly CHAINPATROL_WARNING_URL =\n \"https://app.chainpatrol.io/warning\";\n private static readonly Schema = z.object({\n version: z.literal(1),\n data: z.object({\n domains: z.array(z.string()),\n }),\n });\n\n private mode: Mode;\n private client?: ChainPatrolClient;\n private storage: Storage;\n private redirectUrl?: string | ((url: string) => string);\n private readonly logger = new Logger({ component: \"ThreatDetector\" });\n\n constructor({\n mode,\n storage,\n redirectUrl,\n }: {\n mode: \"local\";\n storage?: Storage;\n redirectUrl?: string | ((url: string) => string);\n });\n\n constructor({\n mode,\n apiKey,\n storage,\n redirectUrl,\n }: {\n mode: \"cloud\";\n apiKey: string;\n storage?: Storage;\n redirectUrl?: string | ((url: string) => string);\n });\n\n constructor({\n mode,\n apiKey,\n proxyUrl,\n storage,\n redirectUrl,\n }: {\n mode: \"cloud\";\n apiKey: string;\n proxyUrl?: string;\n storage?: Storage;\n redirectUrl?: string | ((url: string) => string);\n });\n\n constructor({\n mode = \"cloud\",\n apiKey = \"\",\n storage = Memory(),\n proxyUrl,\n redirectUrl,\n }: {\n mode?: Mode;\n apiKey?: string;\n proxyUrl?: string;\n storage?: Storage;\n redirectUrl?: string | ((url: string) => string);\n }) {\n this.mode = mode;\n this.storage = storage;\n this.redirectUrl = redirectUrl ?? ThreatDetector.CHAINPATROL_WARNING_URL;\n if (mode === \"cloud\") {\n this.client = new ChainPatrolClient({\n apiKey: apiKey,\n baseUrl: proxyUrl,\n });\n }\n }\n\n public async url(url: string): Promise<URLResult> {\n this.logger.debug(\"Checking URL\", { url });\n\n let domains: Domain[];\n try {\n domains = this.generateDomains(url);\n } catch (e) {\n this.logger.error(\"Unable to parse domain\", { url, error: e });\n return {\n ok: false,\n url,\n error:\n e instanceof DomainParseError ? e.message : \"Unable to parse domain\",\n };\n }\n\n this.logger.debug(\"Generated domains\", { domains });\n\n let results = (\n await Promise.all(domains.map((domain) => this.urlHelper(domain, url)))\n ).filter(\n <T extends URLResult>(r: T): r is T extends { ok: true } ? T : never =>\n r.ok\n );\n\n if (results.length === 0) {\n return {\n ok: false,\n url,\n error: \"URL does not have a valid domain\",\n };\n }\n\n this.logger.debug(\"Results for domains\", { results });\n\n if (results.some((r) => r.status === \"IGNORED\")) {\n return {\n ok: true,\n status: \"IGNORED\",\n url,\n };\n }\n\n for (const result of results) {\n if (result.ok && result.status !== \"UNKNOWN\") {\n return result;\n }\n }\n\n return results[0];\n }\n\n private generateDomains(_url: string): Domain[] {\n const domain = this.parseDomainOrThrow(_url);\n\n const domains = [domain];\n\n const parsedDomain = parseDomain(domain);\n if (!parsedDomain.subdomain) {\n return domains;\n }\n\n const subdomainParts = parsedDomain.subdomain?.split(\".\") ?? [];\n\n for (let i = 0; i < subdomainParts.length; i++) {\n const subdomain = subdomainParts.slice(i).join(\".\");\n domains.unshift(`${subdomain}.${domain}` as Domain);\n }\n\n return domains;\n }\n\n private async urlHelper(domain: Domain, url: string): Promise<URLResult> {\n let status = await this.getStatusFromCache(domain);\n\n if (this.mode === \"cloud\" && this.client && status === \"UNKNOWN\") {\n try {\n const res = await this.client.asset.check({\n type: \"URL\",\n content: domain,\n });\n\n // Update cache storage\n this.logger.debug(\"Updating cache\", { domain, status: res.status });\n if (res.status === \"ALLOWED\") {\n this.addDomainToCache(domain, ThreatDetector.StorageKeys.ALLOWLIST);\n } else if (res.status === \"BLOCKED\") {\n this.addDomainToCache(domain, ThreatDetector.StorageKeys.BLOCKLIST);\n }\n\n status = res.status;\n } catch (e) {\n return {\n ok: false,\n url: domain,\n error: \"Unable to check URL\",\n };\n }\n }\n\n let redirectUrl: string | undefined;\n\n if (status === \"BLOCKED\") {\n if (typeof this.redirectUrl === \"function\") {\n redirectUrl = this.redirectUrl(url);\n } else if (typeof this.redirectUrl === \"string\") {\n const newUrl = new URL(this.redirectUrl);\n newUrl.searchParams.set(\"originUrl\", url);\n redirectUrl = newUrl.toString();\n }\n }\n\n return {\n ok: true,\n status,\n url: domain,\n redirectUrl,\n };\n }\n\n public async allow(\n url: string\n ): Promise<\n { ok: true; url: string } | { ok: false; url: string; error: string }\n > {\n try {\n const domain = this.parseDomainOrThrow(url);\n\n this.logger.debug(\"Allowing URL\", { url, domain });\n\n await this.invalidateDomainInCaches(domain);\n await this.addDomainToCache(domain, ThreatDetector.StorageKeys.ALLOWLIST);\n\n return {\n ok: true,\n url: domain,\n };\n } catch (e) {\n this.logger.error(\"Unable to allow URL\", { url, error: e });\n return {\n ok: false,\n url,\n error: \"Unable to allow URL\",\n };\n }\n }\n\n public async block(\n url: string\n ): Promise<\n { ok: true; url: string } | { ok: false; url: string; error: string }\n > {\n try {\n const domain = this.parseDomainOrThrow(url);\n\n this.logger.debug(\"Blocking URL\", { url, domain });\n\n await this.invalidateDomainInCaches(domain);\n await this.addDomainToCache(domain, ThreatDetector.StorageKeys.BLOCKLIST);\n\n return {\n ok: true,\n url: domain,\n };\n } catch (e) {\n this.logger.error(\"Unable to block URL\", { url, error: e });\n return {\n ok: false,\n url,\n error: \"Unable to block URL\",\n };\n }\n }\n\n public async ignore(\n url: string\n ): Promise<\n { ok: true; url: string } | { ok: false; url: string; error: string }\n > {\n try {\n const domain = this.parseDomainOrThrow(url);\n\n this.logger.debug(\"Ignoring URL\", { url, domain });\n\n await this.addDomainToCache(\n domain,\n ThreatDetector.StorageKeys.IGNORELIST\n );\n\n return {\n ok: true,\n url: domain,\n };\n } catch (e) {\n this.logger.error(\"Unable to ignore URL\", { url, error: e });\n return {\n ok: false,\n url,\n error: \"Unable to ignore URL\",\n };\n }\n }\n\n private parseDomainOrThrow(url: string): Domain {\n this.logger.debug(\"Parsing domain\", { url });\n try {\n const normalizedUrl = normalizeUrl(url, {\n stripWWW: false,\n removeTrailingSlash: false,\n });\n\n this.logger.debug(\"Normalized URL\", { from: url, to: normalizedUrl });\n\n const parsedURL = new URL(normalizedUrl);\n\n this.logger.debug(\"Extract domain from URL\", { url: parsedURL.hostname });\n\n const parsedSubdomainResult = parseDomain(parsedURL.hostname);\n\n this.logger.debug(\"Parsed domain\", { parsedSubdomainResult });\n\n if (parsedSubdomainResult.hostname === \"localhost\") {\n throw new DomainParseError(\"ThreatDetector does not support localhost\");\n }\n\n if (parsedSubdomainResult.isIp) {\n throw new DomainParseError(\n \"ThreatDetector does not support IP addresses\"\n );\n }\n\n if (!parsedSubdomainResult.domain) {\n throw new DomainParseError(\"Unable to parse domain\");\n }\n\n const domain = parsedSubdomainResult.domain as Domain;\n\n return domain;\n } catch (e) {\n if (e instanceof DomainParseError) {\n throw e;\n } else {\n this.logger.error(\"Unable to parse domain\", { url, error: e });\n throw new DomainParseError(\"Unable to parse domain\");\n }\n }\n }\n\n private async invalidateDomainInCaches(domain: Domain): Promise<void> {\n await this.invalidateDomainInCache(\n domain,\n ThreatDetector.StorageKeys.ALLOWLIST\n );\n await this.invalidateDomainInCache(\n domain,\n ThreatDetector.StorageKeys.BLOCKLIST\n );\n }\n\n private async invalidateDomainInCache(\n domain: Domain,\n key: string\n ): Promise<void> {\n const data = await this.storage.get(key);\n\n if (!data) {\n return;\n }\n\n const list = await this.getListFromStorage(key);\n\n if (!list.data.domains.includes(domain)) {\n return;\n }\n\n list.data.domains = list.data.domains.filter((u) => u !== domain);\n\n await this.setListInStorage(key, list);\n }\n\n private async addDomainToCache(domain: Domain, key: string): Promise<void> {\n const list = await this.getListFromStorage(key);\n\n if (list.data.domains.includes(domain)) {\n return;\n }\n\n list.data.domains.push(domain);\n\n await this.setListInStorage(key, list);\n }\n\n private async isDomainInList(domain: Domain, key: string): Promise<boolean> {\n const list = await this.getListFromStorage(key);\n return list.data.domains.includes(domain);\n }\n\n private async getListFromStorage(\n key: string\n ): Promise<z.infer<typeof ThreatDetector.Schema>> {\n const data = await this.storage.get(key);\n\n if (!data) {\n const list: z.infer<typeof ThreatDetector.Schema> = {\n version: 1,\n data: {\n domains: [],\n },\n };\n await this.setListInStorage(key, list);\n return list;\n }\n\n const list = ThreatDetector.Schema.parse(JSON.parse(data));\n\n return list;\n }\n\n private async setListInStorage(\n key: string,\n list: z.infer<typeof ThreatDetector.Schema>\n ): Promise<void> {\n await this.storage.set(key, JSON.stringify(list));\n }\n\n private async getStatusFromCache(\n domain: Domain\n ): Promise<DetectorAssetStatus> {\n if (\n await this.isDomainInList(domain, ThreatDetector.StorageKeys.IGNORELIST)\n ) {\n return \"IGNORED\";\n } else if (\n await this.isDomainInList(domain, ThreatDetector.StorageKeys.BLOCKLIST)\n ) {\n return \"BLOCKED\";\n } else if (\n await this.isDomainInList(domain, ThreatDetector.StorageKeys.ALLOWLIST)\n ) {\n return \"ALLOWED\";\n } else {\n return \"UNKNOWN\";\n }\n }\n}\n","// https://developer.mozilla.org/en-US/docs/Web/HTTP/Basics_of_HTTP/Data_URIs\nconst DATA_URL_DEFAULT_MIME_TYPE = 'text/plain';\nconst DATA_URL_DEFAULT_CHARSET = 'us-ascii';\n\nconst testParameter = (name, filters) => filters.some(filter => filter instanceof RegExp ? filter.test(name) : filter === name);\n\nconst supportedProtocols = new Set([\n\t'https:',\n\t'http:',\n\t'file:',\n]);\n\nconst hasCustomProtocol = urlString => {\n\ttry {\n\t\tconst {protocol} = new URL(urlString);\n\t\treturn protocol.endsWith(':') && !supportedProtocols.has(protocol);\n\t} catch {\n\t\treturn false;\n\t}\n};\n\nconst normalizeDataURL = (urlString, {stripHash}) => {\n\tconst match = /^data:(?<type>[^,]*?),(?<data>[^#]*?)(?:#(?<hash>.*))?$/.exec(urlString);\n\n\tif (!match) {\n\t\tthrow new Error(`Invalid URL: ${urlString}`);\n\t}\n\n\tlet {type, data, hash} = match.groups;\n\tconst mediaType = type.split(';');\n\thash = stripHash ? '' : hash;\n\n\tlet isBase64 = false;\n\tif (mediaType[mediaType.length - 1] === 'base64') {\n\t\tmediaType.pop();\n\t\tisBase64 = true;\n\t}\n\n\t// Lowercase MIME type\n\tconst mimeType = mediaType.shift()?.toLowerCase() ?? '';\n\tconst attributes = mediaType\n\t\t.map(attribute => {\n\t\t\tlet [key, value = ''] = attribute.split('=').map(string => string.trim());\n\n\t\t\t// Lowercase `charset`\n\t\t\tif (key === 'charset') {\n\t\t\t\tvalue = value.toLowerCase();\n\n\t\t\t\tif (value === DATA_URL_DEFAULT_CHARSET) {\n\t\t\t\t\treturn '';\n\t\t\t\t}\n\t\t\t}\n\n\t\t\treturn `${key}${value ? `=${value}` : ''}`;\n\t\t})\n\t\t.filter(Boolean);\n\n\tconst normalizedMediaType = [\n\t\t...attributes,\n\t];\n\n\tif (isBase64) {\n\t\tnormalizedMediaType.push('base64');\n\t}\n\n\tif (normalizedMediaType.length > 0 || (mimeType && mimeType !== DATA_URL_DEFAULT_MIME_TYPE)) {\n\t\tnormalizedMediaType.unshift(mimeType);\n\t}\n\n\treturn `data:${normalizedMediaType.join(';')},${isBase64 ? data.trim() : data}${hash ? `#${hash}` : ''}`;\n};\n\nexport default function normalizeUrl(urlString, options) {\n\toptions = {\n\t\tdefaultProtocol: 'http',\n\t\tnormalizeProtocol: true,\n\t\tforceHttp: false,\n\t\tforceHttps: false,\n\t\tstripAuthentication: true,\n\t\tstripHash: false,\n\t\tstripTextFragment: true,\n\t\tstripWWW: true,\n\t\tremoveQueryParameters: [/^utm_\\w+/i],\n\t\tremoveTrailingSlash: true,\n\t\tremoveSingleSlash: true,\n\t\tremoveDirectoryIndex: false,\n\t\tremoveExplicitPort: false,\n\t\tsortQueryParameters: true,\n\t\t...options,\n\t};\n\n\t// Legacy: Append `:` to the protocol if missing.\n\tif (typeof options.defaultProtocol === 'string' && !options.defaultProtocol.endsWith(':')) {\n\t\toptions.defaultProtocol = `${options.defaultProtocol}:`;\n\t}\n\n\turlString = urlString.trim();\n\n\t// Data URL\n\tif (/^data:/i.test(urlString)) {\n\t\treturn normalizeDataURL(urlString, options);\n\t}\n\n\tif (hasCustomProtocol(urlString)) {\n\t\treturn urlString;\n\t}\n\n\tconst hasRelativeProtocol = urlString.startsWith('//');\n\tconst isRelativeUrl = !hasRelativeProtocol && /^\\.*\\//.test(urlString);\n\n\t// Prepend protocol\n\tif (!isRelativeUrl) {\n\t\turlString = urlString.replace(/^(?!(?:\\w+:)?\\/\\/)|^\\/\\//, options.defaultProtocol);\n\t}\n\n\tconst urlObject = new URL(urlString);\n\n\tif (options.forceHttp && options.forceHttps) {\n\t\tthrow new Error('The `forceHttp` and `forceHttps` options cannot be used together');\n\t}\n\n\tif (options.forceHttp && urlObject.protocol === 'https:') {\n\t\turlObject.protocol = 'http:';\n\t}\n\n\tif (options.forceHttps && urlObject.protocol === 'http:') {\n\t\turlObject.protocol = 'https:';\n\t}\n\n\t// Remove auth\n\tif (options.stripAuthentication) {\n\t\turlObject.username = '';\n\t\turlObject.password = '';\n\t}\n\n\t// Remove hash\n\tif (options.stripHash) {\n\t\turlObject.hash = '';\n\t} else if (options.stripTextFragment) {\n\t\turlObject.hash = urlObject.hash.replace(/#?:~:text.*?$/i, '');\n\t}\n\n\t// Remove duplicate slashes if not preceded by a protocol\n\t// NOTE: This could be implemented using a single negative lookbehind\n\t// regex, but we avoid that to maintain compatibility with older js engines\n\t// which do not have support for that feature.\n\tif (urlObject.pathname) {\n\t\t// TODO: Replace everything below with `urlObject.pathname = urlObject.pathname.replace(/(?<!\\b[a-z][a-z\\d+\\-.]{1,50}:)\\/{2,}/g, '/');` when Safari supports negative lookbehind.\n\n\t\t// Split the string by occurrences of this protocol regex, and perform\n\t\t// duplicate-slash replacement on the strings between those occurrences\n\t\t// (if any).\n\t\tconst protocolRegex = /\\b[a-z][a-z\\d+\\-.]{1,50}:\\/\\//g;\n\n\t\tlet lastIndex = 0;\n\t\tlet result = '';\n\t\tfor (;;) {\n\t\t\tconst match = protocolRegex.exec(urlObject.pathname);\n\t\t\tif (!match) {\n\t\t\t\tbreak;\n\t\t\t}\n\n\t\t\tconst protocol = match[0];\n\t\t\tconst protocolAtIndex = match.index;\n\t\t\tconst intermediate = urlObject.pathname.slice(lastIndex, protocolAtIndex);\n\n\t\t\tresult += intermediate.replace(/\\/{2,}/g, '/');\n\t\t\tresult += protocol;\n\t\t\tlastIndex = protocolAtIndex + protocol.length;\n\t\t}\n\n\t\tconst remnant = urlObject.pathname.slice(lastIndex, urlObject.pathname.length);\n\t\tresult += remnant.replace(/\\/{2,}/g, '/');\n\n\t\turlObject.pathname = result;\n\t}\n\n\t// Decode URI octets\n\tif (urlObject.pathname) {\n\t\ttry {\n\t\t\turlObject.pathname = decodeURI(urlObject.pathname);\n\t\t} catch {}\n\t}\n\n\t// Remove directory index\n\tif (options.removeDirectoryIndex === true) {\n\t\toptions.removeDirectoryIndex = [/^index\\.[a-z]+$/];\n\t}\n\n\tif (Array.isArray(options.removeDirectoryIndex) && options.removeDirectoryIndex.length > 0) {\n\t\tlet pathComponents = urlObject.pathname.split('/');\n\t\tconst lastComponent = pathComponents[pathComponents.length - 1];\n\n\t\tif (testParameter(lastComponent, options.removeDirectoryIndex)) {\n\t\t\tpathComponents = pathComponents.slice(0, -1);\n\t\t\turlObject.pathname = pathComponents.slice(1).join('/') + '/';\n\t\t}\n\t}\n\n\tif (urlObject.hostname) {\n\t\t// Remove trailing dot\n\t\turlObject.hostname = urlObject.hostname.replace(/\\.$/, '');\n\n\t\t// Remove `www.`\n\t\tif (options.stripWWW && /^www\\.(?!www\\.)[a-z\\-\\d]{1,63}\\.[a-z.\\-\\d]{2,63}$/.test(urlObject.hostname)) {\n\t\t\t// Each label should be max 63 at length (min: 1).\n\t\t\t// Source: https://en.wikipedia.org/wiki/Hostname#Restrictions_on_valid_host_names\n\t\t\t// Each TLD should be up to 63 characters long (min: 2).\n\t\t\t// It is technically possible to have a single character TLD, but none currently exist.\n\t\t\turlObject.hostname = urlObject.hostname.replace(/^www\\./, '');\n\t\t}\n\t}\n\n\t// Remove query unwanted parameters\n\tif (Array.isArray(options.removeQueryParameters)) {\n\t\t// eslint-disable-next-line unicorn/no-useless-spread -- We are intentionally spreading to get a copy.\n\t\tfor (const key of [...urlObject.searchParams.keys()]) {\n\t\t\tif (testParameter(key, options.removeQueryParameters)) {\n\t\t\t\turlObject.searchParams.delete(key);\n\t\t\t}\n\t\t}\n\t}\n\n\tif (!Array.isArray(options.keepQueryParameters) && options.removeQueryParameters === true) {\n\t\turlObject.search = '';\n\t}\n\n\t// Keep wanted query parameters\n\tif (Array.isArray(options.keepQueryParameters) && options.keepQueryParameters.length > 0) {\n\t\t// eslint-disable-next-line unicorn/no-useless-spread -- We are intentionally spreading to get a copy.\n\t\tfor (const key of [...urlObject.searchParams.keys()]) {\n\t\t\tif (!testParameter(key, options.keepQueryParameters)) {\n\t\t\t\turlObject.searchParams.delete(key);\n\t\t\t}\n\t\t}\n\t}\n\n\t// Sort query parameters\n\tif (options.sortQueryParameters) {\n\t\turlObject.searchParams.sort();\n\n\t\t// Calling `.sort()` encodes the search parameters, so we need to decode them again.\n\t\ttry {\n\t\t\turlObject.search = decodeURIComponent(urlObject.search);\n\t\t} catch {}\n\t}\n\n\tif (options.removeTrailingSlash) {\n\t\turlObject.pathname = urlObject.pathname.replace(/\\/$/, '');\n\t}\n\n\t// Remove an explicit port number, excluding a default port number, if applicable\n\tif (options.removeExplicitPort && urlObject.port) {\n\t\turlObject.port = '';\n\t}\n\n\tconst oldUrlString = urlString;\n\n\t// Take advantage of many of the Node `url` normalizations\n\turlString = urlObject.toString();\n\n\tif (!options.removeSingleSlash && urlObject.pathname === '/' && !oldUrlString.endsWith('/') && urlObject.hash === '') {\n\t\turlString = urlString.replace(/\\/$/, '');\n\t}\n\n\t// Remove ending `/` unless removeSingleSlash is false\n\tif ((options.removeTrailingSlash || urlObject.pathname === '/') && urlObject.hash === '' && options.removeSingleSlash) {\n\t\turlString = urlString.replace(/\\/$/, '');\n\t}\n\n\t// Restore relative protocol, if applicable\n\tif (hasRelativeProtocol && !options.normalizeProtocol) {\n\t\turlString = urlString.replace(/^http:\\/\\//, '//');\n\t}\n\n\t// Remove http/https\n\tif (options.stripProtocol) {\n\t\turlString = urlString.replace(/^(?:https?:)?\\/\\//, '');\n\t}\n\n\treturn urlString;\n}\n","import { Logger } from \"./logger\";\n\nexport type ChainPatrolClientOptions = {\n apiKey: string;\n baseUrl?: string;\n};\n\ntype ApiRequest = {\n path: string[];\n method: \"GET\" | \"POST\" | \"PUT\" | \"DELETE\";\n body?: unknown;\n};\n\nexport type AssetType = \"URL\" | \"PAGE\" | \"ADDRESS\";\nexport type AssetStatus = \"ALLOWED\" | \"BLOCKED\" | \"UNKNOWN\";\n\nfunction trimTrailingSlashes(url: string): string {\n return url.replace(/\\/+$/, \"\");\n}\n\nexport class ChainPatrolClient {\n public readonly baseUrl: string;\n private readonly apiKey: string;\n private readonly logger = new Logger({ component: \"ChainPatrolClient\" });\n\n constructor(options: ChainPatrolClientOptions) {\n this.baseUrl = options.baseUrl ?? \"https://app.chainpatrol.io/api/\";\n if (!options.apiKey) {\n throw new Error(\"ChainPatrol API key is required\");\n }\n this.apiKey = options.apiKey;\n }\n\n private async fetch<TResult = unknown>(req: ApiRequest): Promise<TResult> {\n const url = `${trimTrailingSlashes(this.baseUrl)}/${req.path.join(\"/\")}`;\n this.logger.debug(\"fetch\", { url, req });\n const res = await fetch(url, {\n method: req.method,\n headers: {\n \"Content-Type\": \"application/json\",\n \"X-Api-Key\": this.apiKey,\n },\n body: JSON.stringify(req.body),\n });\n if (!res.ok) {\n throw new Error(await res.text());\n }\n return res.json();\n }\n\n public get asset() {\n return {\n check: async (req: {\n type: AssetType;\n content: string;\n }): Promise<{\n /**\n * \"ALLOWED\" - the asset is on the allowlist\n * \"BLOCKED\" - the asset is on the blocklist\n * \"UNKNOWN\" - the asset's status is not known\n */\n status: AssetStatus;\n /**\n * If the asset is allowed or blocked, this will be the reason why.\n * ChainPatrol aggregates data from multiple sources, so this will\n * tell you which source blocked or allowed the asset.\n *\n * ex. 'eth-phishing-detect' - the asset is on MetaMask's blocklist\n * 'reported' - the asset is on ChainPatrol's blocklist because\n * it was reported by a user\n */\n reason?: string;\n }> => {\n return await this.fetch<{\n status: AssetStatus;\n reason?: string;\n }>({\n path: [\"v2\", \"asset\", \"check\"],\n method: \"POST\",\n body: req,\n });\n },\n\n list: async (req: {\n /**\n * Asset type\n */\n type: AssetType;\n /**\n * Status of the assets to retrieve\n */\n status: AssetStatus;\n /**\n * The start date to list assets from. This should be in the format `YYYY-MM-DD` and is inclusive.\n */\n startDate?: string;\n /**\n * The end date to list assets from. This should be in the format `YYYY-MM-DD` and is inclusive.\n */\n endDate?: string;\n }): Promise<\n {\n content: string;\n type: AssetType;\n status: AssetStatus;\n }[]\n > => {\n return await this.fetch<\n {\n content: string;\n type: AssetType;\n status: AssetStatus;\n }[]\n >({\n path: [\"v2\", \"asset\", \"list\"],\n method: \"POST\",\n body: req,\n });\n },\n };\n }\n\n public get report() {\n return {\n create: async (req: {\n /** Report title */\n title: string;\n /** Report description */\n description: string;\n /** List of assets to report with the proposed status */\n assets: {\n content: string;\n status: AssetStatus;\n }[];\n /** Organization slug (provide this or `discordGuildId`) */\n organizationSlug?: string;\n /** Discord guild ID (provide this or `organizationSlug`) */\n discordGuildId?: string;\n /** Optional raw input of the assets */\n rawAssetsInput?: string;\n /** Optional List of URLs of images to attach to the report */\n attachmentUrls?: string[];\n /** Optional contact information of the reporter */\n contactInfo?: string;\n /** Optional ID of the reporter if they are a member on ChainPatrol */\n reporterId?: number;\n /**\n * Optional information about the reporter if they are reporting from\n * a platform other than ChainPatrol\n */\n externalReporter?: {\n platform: string;\n platformIdentifier: string;\n avatarUrl?: string;\n };\n }) => {\n return await this.fetch<{\n id: number;\n createdAt: string;\n organization: {\n id: number;\n slug: string;\n name: string;\n };\n }>({\n path: [\"v2\", \"report\", \"create\"],\n method: \"POST\",\n body: req,\n });\n },\n };\n }\n}\n","export * from \"./extension\";\nexport * from \"./browser\";\nexport * from \"./memory\";\nexport { defineStorage } from \"./define-storage\";\nexport * from \"./types\";\n","import { ThreatDetector } from \"../detector\";\nimport { Storage } from \"./types\";\n\nexport interface Context {\n keys: string[];\n}\n\nexport function defineStorage<T extends Storage>(\n config: (ctx: Context) => T\n): () => T {\n return () =>\n config({\n keys: Object.values(ThreatDetector.StorageKeys),\n });\n}\n","import { defineStorage } from \"./define-storage\";\n\nexport const Extension = defineStorage(({ keys }) => {\n return {\n get: async (key: string) => {\n const result = await chrome.storage.local.get(key);\n return result[key];\n },\n set: async (key: string, value: string) => {\n await chrome.storage.local.set({ [key]: value });\n },\n delete: async (key: string) => {\n await chrome.storage.local.remove(key);\n },\n size: async () => {\n const usageBytes = await chrome.storage.local.getBytesInUse(keys);\n return usageBytes;\n },\n };\n});\n","import { defineStorage } from \"./define-storage\";\n\nfunction isStorageAvailable(type: \"localStorage\" | \"sessionStorage\") {\n let storage;\n try {\n storage = window[type];\n const x = \"__storage_test__\";\n storage.setItem(x, x);\n storage.removeItem(x);\n return true;\n } catch (e) {\n return (\n e instanceof DOMException &&\n // everything except Firefox\n (e.code === 22 ||\n // Firefox\n e.code === 1014 ||\n // test name field too, because code might not be present\n // everything except Firefox\n e.name === \"QuotaExceededError\" ||\n // Firefox\n e.name === \"NS_ERROR_DOM_QUOTA_REACHED\") &&\n // acknowledge QuotaExceededError only if there's something already stored\n storage &&\n storage.length !== 0\n );\n }\n}\n\nexport const Browser = defineStorage(({ keys }) => {\n if (!isStorageAvailable(\"localStorage\")) {\n throw new Error(\"localStorage is not available\");\n }\n\n return {\n get: async (key: string) => {\n return localStorage.getItem(key);\n },\n set: async (key: string, value: string) => {\n localStorage.setItem(key, value);\n },\n delete: async (key: string) => {\n localStorage.removeItem(key);\n },\n size: async () => {\n let total = 0;\n for (let i = 0; i < localStorage.length; i++) {\n const key = localStorage.key(i);\n if (key && keys.includes(key)) {\n total += localStorage.getItem(key)?.length ?? 0;\n }\n }\n return total;\n },\n };\n});\n","import { defineStorage } from \"./define-storage\";\n\nexport const Memory = defineStorage(() => {\n const storage = new Map<string, string>();\n return {\n get: async (key: string) => {\n return storage.get(key) || null;\n },\n set: async (key: string, value: string) => {\n storage.set(key, value);\n },\n delete: async (key: string) => {\n storage.delete(key);\n },\n size: async () => {\n let total = 0;\n for (const value of storage.values()) {\n total += value.length;\n }\n return total;\n },\n };\n});\n"]}
|
package/dist/index.mjs
CHANGED
|
@@ -495,7 +495,18 @@ var ChainPatrolClient = class {
|
|
|
495
495
|
list: (req) => __async(this, null, function* () {
|
|
496
496
|
return yield this.fetch({
|
|
497
497
|
path: ["v2", "asset", "list"],
|
|
498
|
-
method: "
|
|
498
|
+
method: "POST",
|
|
499
|
+
body: req
|
|
500
|
+
});
|
|
501
|
+
})
|
|
502
|
+
};
|
|
503
|
+
}
|
|
504
|
+
get report() {
|
|
505
|
+
return {
|
|
506
|
+
create: (req) => __async(this, null, function* () {
|
|
507
|
+
return yield this.fetch({
|
|
508
|
+
path: ["v2", "report", "create"],
|
|
509
|
+
method: "POST",
|
|
499
510
|
body: req
|
|
500
511
|
});
|
|
501
512
|
})
|
package/dist/index.mjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/events.ts","../src/logger.ts","../src/relay.ts","../src/detector.ts","../../../node_modules/normalize-url/index.js","../src/client.ts","../src/storage/index.ts","../src/storage/define-storage.ts","../src/storage/extension.ts","../src/storage/browser.ts","../src/storage/memory.ts"],"names":["LogLevel","list"],"mappings":"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","sourcesContent":["const ContinueAtOwnRisk = \"CHAINPATROL_CONTINUE_AT_OWN_RISK\";\nconst IgnorelistUpdated = \"CHAINPATROL_IGNORELIST_UPDATED\";\nconst CloseCurrentTab = \"CHAINPATROL_CLOSE_CURRENT_TAB\";\n\nexport const Events = {\n ContinueAtOwnRisk,\n IgnorelistUpdated,\n CloseCurrentTab,\n} as const;\n\nexport type EventData = {\n [ContinueAtOwnRisk]: {\n domain: string;\n };\n [IgnorelistUpdated]: {\n domain: string;\n };\n [CloseCurrentTab]: {};\n};\n","export enum LogLevel {\n DEBUG,\n INFO,\n WARN,\n ERROR,\n NONE,\n}\n\nexport class Logger {\n private meta: Record<string, unknown> = {};\n private minLevel: LogLevel;\n\n constructor(\n meta?: Record<string, unknown>,\n minLevel: LogLevel = LogLevel.NONE\n ) {\n if (meta) {\n this.meta = meta;\n }\n this.minLevel = minLevel;\n }\n\n public with(fields: Record<string, unknown>) {\n return new Logger({ ...this.meta, ...fields }, this.minLevel);\n }\n\n public debug(message: string, fields?: Record<string, unknown>) {\n this.log(LogLevel.DEBUG, message, fields);\n }\n\n public info(message: string, fields?: Record<string, unknown>) {\n this.log(LogLevel.INFO, message, fields);\n }\n\n public warn(message: string, fields?: Record<string, unknown>) {\n this.log(LogLevel.WARN, message, fields);\n }\n\n public error(message: string, fields?: Record<string, unknown>) {\n this.log(LogLevel.ERROR, message, fields);\n }\n\n private log(\n level: LogLevel,\n message: string,\n fields?: Record<string, unknown>\n ) {\n if (level < this.minLevel) {\n return; // Skip logging if log level is lower than minimum level\n }\n\n const logObj = { message, data: { ...fields }, ...this.meta };\n const logString = JSON.stringify(logObj, null, 2);\n console.log(`[${LogLevel[level].toUpperCase()}] ${logString}`);\n }\n}\n","import { EventData } from \"./events\";\nimport { Logger } from \"./logger\";\n\ntype Message<EventType extends keyof EventData> = {\n type: EventType;\n data: EventData[EventType];\n _meta: {\n id: string;\n origin: string;\n };\n};\n\nfunction getExtensionRuntime(): typeof chrome.runtime {\n if ((globalThis as any).browser?.runtime) {\n return (globalThis as any).browser.runtime;\n }\n if (globalThis.chrome?.runtime) {\n return globalThis.chrome.runtime;\n }\n throw new Error(\"No extension runtime found\");\n}\n\nfunction isExtensionHost() {\n return (\n !!(globalThis as any).browser?.runtime ||\n !!(globalThis as any).chrome?.runtime\n );\n}\n\nfunction isContentScript() {\n return isExtensionHost() && isBrowserHost();\n}\n\nfunction isBackgroundScript() {\n return isExtensionHost() && !isBrowserHost();\n}\n\nfunction isBrowserHost() {\n return !!(globalThis as any).window;\n}\n\ntype Handle = {\n addListener: (callback: (message: any) => void) => void;\n removeListener: (callback: (message: any) => void) => void;\n postMessage: (message: any) => void;\n};\n\nfunction getBackgroundScriptHandle(): Handle {\n const runtime = getExtensionRuntime();\n return {\n addListener: (callback: (message: any) => void) => {\n runtime.onMessage.addListener(callback);\n },\n removeListener: (callback: (message: any) => void) => {\n runtime.onMessage.removeListener(callback);\n },\n postMessage: async (message: any) => {\n const [tab] = await globalThis.chrome.tabs.query({\n active: true,\n lastFocusedWindow: true,\n });\n if (!tab.id || tab.id === globalThis.chrome.tabs.TAB_ID_NONE) {\n console.error(\"No active tab found\");\n return;\n }\n globalThis.chrome.tabs.sendMessage(tab.id, message);\n },\n };\n}\n\nfunction getContentScriptHandle(): Handle {\n const runtime = getExtensionRuntime();\n return {\n addListener: (callback: (message: any) => void) => {\n runtime.onMessage.addListener(callback);\n },\n removeListener: (callback: (message: any) => void) => {\n runtime.onMessage.removeListener(callback);\n },\n postMessage: async (message: any) => {\n runtime.sendMessage(message).catch((error) => {\n console.error(\"Failed to send message\", { message, error });\n });\n },\n };\n}\n\nfunction getBrowserHandle(): Handle {\n return {\n addListener: (callback: (message: any) => void) => {\n globalThis.window.addEventListener(\"message\", (event) => {\n if (event.source !== globalThis.window) {\n return;\n }\n callback(event.data);\n });\n },\n removeListener: (callback: (message: any) => void) => {\n globalThis.window.removeEventListener(\"message\", callback);\n },\n postMessage: (message: any) => {\n globalThis.window.postMessage(message, \"*\");\n },\n };\n}\n\n/**\n * Relay contains methods for implementing an event relay. It is used to\n * forward events between Javascript contexts:\n *\n * `<window>` <-> `<content script>` <-> `<background script>`\n *\n * Call `Relay.send` to send an event from one context to another. Call\n * `Relay.on` to listen for events in the current context. Call `Relay.run`\n * to start listening for events in the current context and forward them\n * to all other contexts.\n */\nexport class Relay {\n protected static handles: Handle[] = [];\n private static readonly logger = new Logger({ component: \"Relay\" });\n\n static {\n if (isBackgroundScript()) {\n Relay.logger.info(\"Detected background script\");\n Relay.handles.push(getBackgroundScriptHandle());\n } else if (isContentScript()) {\n Relay.logger.info(\"Detected content script\");\n Relay.handles.push(getContentScriptHandle());\n Relay.handles.push(getBrowserHandle());\n } else if (isBrowserHost()) {\n Relay.logger.info(\"Detected browser host\");\n Relay.handles.push(getBrowserHandle());\n }\n }\n\n public static send<EventType extends keyof EventData>(\n type: EventType,\n data: EventData[EventType]\n ) {\n const message = {\n type,\n data,\n _meta: {\n id: Math.random().toString(36).substring(2, 9),\n origin: globalThis.location.origin,\n },\n } satisfies Message<EventType>;\n\n Relay.logger.debug(\"Sending message\", message);\n\n for (const handle of Relay.handles) {\n handle.postMessage(message);\n }\n }\n\n public static run(events: (keyof EventData)[]) {\n const listeners = new Set<(message: any) => void>();\n\n for (const handle of Relay.handles) {\n const listener = Relay.handleMessage.bind(null, handle, events);\n listeners.add(listener);\n handle.addListener(listener);\n }\n\n Relay.logger.debug(\"Started relay\", { events });\n\n return () => {\n for (const handle of Relay.handles) {\n for (const listener of listeners) {\n handle.removeListener(listener);\n }\n }\n\n Relay.logger.debug(\"Stopped relay\", { events });\n };\n }\n\n private static handleMessage(\n sourceHandle: Handle,\n events: (keyof EventData)[],\n message: any\n ) {\n if (!events.includes(message.type)) {\n Relay.logger.debug(\"Ignoring message\", { message });\n return;\n }\n\n const destinationHandles = Relay.handles.filter(\n (handle) => handle !== sourceHandle\n );\n\n for (const destinationHandle of destinationHandles) {\n destinationHandle.postMessage(message);\n }\n }\n\n public static on<EventType extends keyof EventData>(\n targetEvent: EventType,\n callback: (data: EventData[EventType]) => void\n ) {\n const listeners = new Set<(message: any) => void>();\n for (const handle of Relay.handles) {\n const listener = (message: any) => {\n if (message.type !== targetEvent) {\n Relay.logger.debug(\"Ignoring message\", { message });\n return;\n }\n callback(message.data);\n };\n listeners.add(listener);\n handle.addListener(listener);\n }\n\n return () => {\n for (const handle of Relay.handles) {\n for (const listener of listeners) {\n handle.removeListener(listener);\n }\n }\n };\n }\n}\n","import { parse as parseDomain } from \"tldts\";\nimport normalizeUrl from \"normalize-url\";\nimport { z } from \"zod\";\n\nimport { AssetStatus, ChainPatrolClient } from \"./client\";\nimport { Memory } from \"./storage\";\nimport type { Storage } from \"./storage/types\";\nimport { Logger } from \"./logger\";\n\ntype Prettify<T> = T extends infer U ? (U extends string ? U : never) : never;\n\nexport type DetectorAssetStatus = Prettify<AssetStatus | \"IGNORED\">;\n\ntype Mode = \"cloud\" | \"local\";\n\n// Branded type for domain strings\ntype Domain = string & { __domain: never };\n\nexport type URLResult =\n | {\n ok: true;\n status: DetectorAssetStatus;\n url: string;\n redirectUrl?: string;\n }\n | {\n ok: false;\n url: string;\n error: string;\n };\n\nexport class DomainParseError extends Error {\n constructor(message: string) {\n super(message);\n this.name = \"DomainParseError\";\n }\n}\n\nexport class ThreatDetector {\n static StorageKeys = {\n ALLOWLIST: \"chainpatrol.allowed\",\n BLOCKLIST: \"chainpatrol.blocked\",\n IGNORELIST: \"chainpatrol.ignored\",\n };\n\n private static readonly CHAINPATROL_WARNING_URL =\n \"https://app.chainpatrol.io/warning\";\n private static readonly Schema = z.object({\n version: z.literal(1),\n data: z.object({\n domains: z.array(z.string()),\n }),\n });\n\n private mode: Mode;\n private client?: ChainPatrolClient;\n private storage: Storage;\n private redirectUrl?: string | ((url: string) => string);\n private readonly logger = new Logger({ component: \"ThreatDetector\" });\n\n constructor({\n mode,\n storage,\n redirectUrl,\n }: {\n mode: \"local\";\n storage?: Storage;\n redirectUrl?: string | ((url: string) => string);\n });\n\n constructor({\n mode,\n apiKey,\n storage,\n redirectUrl,\n }: {\n mode: \"cloud\";\n apiKey: string;\n storage?: Storage;\n redirectUrl?: string | ((url: string) => string);\n });\n\n constructor({\n mode,\n apiKey,\n proxyUrl,\n storage,\n redirectUrl,\n }: {\n mode: \"cloud\";\n apiKey: string;\n proxyUrl?: string;\n storage?: Storage;\n redirectUrl?: string | ((url: string) => string);\n });\n\n constructor({\n mode = \"cloud\",\n apiKey = \"\",\n storage = Memory(),\n proxyUrl,\n redirectUrl,\n }: {\n mode?: Mode;\n apiKey?: string;\n proxyUrl?: string;\n storage?: Storage;\n redirectUrl?: string | ((url: string) => string);\n }) {\n this.mode = mode;\n this.storage = storage;\n this.redirectUrl = redirectUrl ?? ThreatDetector.CHAINPATROL_WARNING_URL;\n if (mode === \"cloud\") {\n this.client = new ChainPatrolClient({\n apiKey: apiKey,\n baseUrl: proxyUrl,\n });\n }\n }\n\n public async url(url: string): Promise<URLResult> {\n this.logger.debug(\"Checking URL\", { url });\n\n let domains: Domain[];\n try {\n domains = this.generateDomains(url);\n } catch (e) {\n this.logger.error(\"Unable to parse domain\", { url, error: e });\n return {\n ok: false,\n url,\n error:\n e instanceof DomainParseError ? e.message : \"Unable to parse domain\",\n };\n }\n\n this.logger.debug(\"Generated domains\", { domains });\n\n let results = (\n await Promise.all(domains.map((domain) => this.urlHelper(domain, url)))\n ).filter(\n <T extends URLResult>(r: T): r is T extends { ok: true } ? T : never =>\n r.ok\n );\n\n if (results.length === 0) {\n return {\n ok: false,\n url,\n error: \"URL does not have a valid domain\",\n };\n }\n\n this.logger.debug(\"Results for domains\", { results });\n\n if (results.some((r) => r.status === \"IGNORED\")) {\n return {\n ok: true,\n status: \"IGNORED\",\n url,\n };\n }\n\n for (const result of results) {\n if (result.ok && result.status !== \"UNKNOWN\") {\n return result;\n }\n }\n\n return results[0];\n }\n\n private generateDomains(_url: string): Domain[] {\n const domain = this.parseDomainOrThrow(_url);\n\n const domains = [domain];\n\n const parsedDomain = parseDomain(domain);\n if (!parsedDomain.subdomain) {\n return domains;\n }\n\n const subdomainParts = parsedDomain.subdomain?.split(\".\") ?? [];\n\n for (let i = 0; i < subdomainParts.length; i++) {\n const subdomain = subdomainParts.slice(i).join(\".\");\n domains.unshift(`${subdomain}.${domain}` as Domain);\n }\n\n return domains;\n }\n\n private async urlHelper(domain: Domain, url: string): Promise<URLResult> {\n let status = await this.getStatusFromCache(domain);\n\n if (this.mode === \"cloud\" && this.client && status === \"UNKNOWN\") {\n try {\n const res = await this.client.asset.check({\n type: \"URL\",\n content: domain,\n });\n\n // Update cache storage\n this.logger.debug(\"Updating cache\", { domain, status: res.status });\n if (res.status === \"ALLOWED\") {\n this.addDomainToCache(domain, ThreatDetector.StorageKeys.ALLOWLIST);\n } else if (res.status === \"BLOCKED\") {\n this.addDomainToCache(domain, ThreatDetector.StorageKeys.BLOCKLIST);\n }\n\n status = res.status;\n } catch (e) {\n return {\n ok: false,\n url: domain,\n error: \"Unable to check URL\",\n };\n }\n }\n\n let redirectUrl: string | undefined;\n\n if (status === \"BLOCKED\") {\n if (typeof this.redirectUrl === \"function\") {\n redirectUrl = this.redirectUrl(url);\n } else if (typeof this.redirectUrl === \"string\") {\n const newUrl = new URL(this.redirectUrl);\n newUrl.searchParams.set(\"originUrl\", url);\n redirectUrl = newUrl.toString();\n }\n }\n\n return {\n ok: true,\n status,\n url: domain,\n redirectUrl,\n };\n }\n\n public async allow(\n url: string\n ): Promise<\n { ok: true; url: string } | { ok: false; url: string; error: string }\n > {\n try {\n const domain = this.parseDomainOrThrow(url);\n\n this.logger.debug(\"Allowing URL\", { url, domain });\n\n await this.invalidateDomainInCaches(domain);\n await this.addDomainToCache(domain, ThreatDetector.StorageKeys.ALLOWLIST);\n\n return {\n ok: true,\n url: domain,\n };\n } catch (e) {\n this.logger.error(\"Unable to allow URL\", { url, error: e });\n return {\n ok: false,\n url,\n error: \"Unable to allow URL\",\n };\n }\n }\n\n public async block(\n url: string\n ): Promise<\n { ok: true; url: string } | { ok: false; url: string; error: string }\n > {\n try {\n const domain = this.parseDomainOrThrow(url);\n\n this.logger.debug(\"Blocking URL\", { url, domain });\n\n await this.invalidateDomainInCaches(domain);\n await this.addDomainToCache(domain, ThreatDetector.StorageKeys.BLOCKLIST);\n\n return {\n ok: true,\n url: domain,\n };\n } catch (e) {\n this.logger.error(\"Unable to block URL\", { url, error: e });\n return {\n ok: false,\n url,\n error: \"Unable to block URL\",\n };\n }\n }\n\n public async ignore(\n url: string\n ): Promise<\n { ok: true; url: string } | { ok: false; url: string; error: string }\n > {\n try {\n const domain = this.parseDomainOrThrow(url);\n\n this.logger.debug(\"Ignoring URL\", { url, domain });\n\n await this.addDomainToCache(\n domain,\n ThreatDetector.StorageKeys.IGNORELIST\n );\n\n return {\n ok: true,\n url: domain,\n };\n } catch (e) {\n this.logger.error(\"Unable to ignore URL\", { url, error: e });\n return {\n ok: false,\n url,\n error: \"Unable to ignore URL\",\n };\n }\n }\n\n private parseDomainOrThrow(url: string): Domain {\n this.logger.debug(\"Parsing domain\", { url });\n try {\n const normalizedUrl = normalizeUrl(url, {\n stripWWW: false,\n removeTrailingSlash: false,\n });\n\n this.logger.debug(\"Normalized URL\", { from: url, to: normalizedUrl });\n\n const parsedURL = new URL(normalizedUrl);\n\n this.logger.debug(\"Extract domain from URL\", { url: parsedURL.hostname });\n\n const parsedSubdomainResult = parseDomain(parsedURL.hostname);\n\n this.logger.debug(\"Parsed domain\", { parsedSubdomainResult });\n\n if (parsedSubdomainResult.hostname === \"localhost\") {\n throw new DomainParseError(\"ThreatDetector does not support localhost\");\n }\n\n if (parsedSubdomainResult.isIp) {\n throw new DomainParseError(\n \"ThreatDetector does not support IP addresses\"\n );\n }\n\n if (!parsedSubdomainResult.domain) {\n throw new DomainParseError(\"Unable to parse domain\");\n }\n\n const domain = parsedSubdomainResult.domain as Domain;\n\n return domain;\n } catch (e) {\n if (e instanceof DomainParseError) {\n throw e;\n } else {\n this.logger.error(\"Unable to parse domain\", { url, error: e });\n throw new DomainParseError(\"Unable to parse domain\");\n }\n }\n }\n\n private async invalidateDomainInCaches(domain: Domain): Promise<void> {\n await this.invalidateDomainInCache(\n domain,\n ThreatDetector.StorageKeys.ALLOWLIST\n );\n await this.invalidateDomainInCache(\n domain,\n ThreatDetector.StorageKeys.BLOCKLIST\n );\n }\n\n private async invalidateDomainInCache(\n domain: Domain,\n key: string\n ): Promise<void> {\n const data = await this.storage.get(key);\n\n if (!data) {\n return;\n }\n\n const list = await this.getListFromStorage(key);\n\n if (!list.data.domains.includes(domain)) {\n return;\n }\n\n list.data.domains = list.data.domains.filter((u) => u !== domain);\n\n await this.setListInStorage(key, list);\n }\n\n private async addDomainToCache(domain: Domain, key: string): Promise<void> {\n const list = await this.getListFromStorage(key);\n\n if (list.data.domains.includes(domain)) {\n return;\n }\n\n list.data.domains.push(domain);\n\n await this.setListInStorage(key, list);\n }\n\n private async isDomainInList(domain: Domain, key: string): Promise<boolean> {\n const list = await this.getListFromStorage(key);\n return list.data.domains.includes(domain);\n }\n\n private async getListFromStorage(\n key: string\n ): Promise<z.infer<typeof ThreatDetector.Schema>> {\n const data = await this.storage.get(key);\n\n if (!data) {\n const list: z.infer<typeof ThreatDetector.Schema> = {\n version: 1,\n data: {\n domains: [],\n },\n };\n await this.setListInStorage(key, list);\n return list;\n }\n\n const list = ThreatDetector.Schema.parse(JSON.parse(data));\n\n return list;\n }\n\n private async setListInStorage(\n key: string,\n list: z.infer<typeof ThreatDetector.Schema>\n ): Promise<void> {\n await this.storage.set(key, JSON.stringify(list));\n }\n\n private async getStatusFromCache(\n domain: Domain\n ): Promise<DetectorAssetStatus> {\n if (\n await this.isDomainInList(domain, ThreatDetector.StorageKeys.IGNORELIST)\n ) {\n return \"IGNORED\";\n } else if (\n await this.isDomainInList(domain, ThreatDetector.StorageKeys.BLOCKLIST)\n ) {\n return \"BLOCKED\";\n } else if (\n await this.isDomainInList(domain, ThreatDetector.StorageKeys.ALLOWLIST)\n ) {\n return \"ALLOWED\";\n } else {\n return \"UNKNOWN\";\n }\n }\n}\n","// https://developer.mozilla.org/en-US/docs/Web/HTTP/Basics_of_HTTP/Data_URIs\nconst DATA_URL_DEFAULT_MIME_TYPE = 'text/plain';\nconst DATA_URL_DEFAULT_CHARSET = 'us-ascii';\n\nconst testParameter = (name, filters) => filters.some(filter => filter instanceof RegExp ? filter.test(name) : filter === name);\n\nconst supportedProtocols = new Set([\n\t'https:',\n\t'http:',\n\t'file:',\n]);\n\nconst hasCustomProtocol = urlString => {\n\ttry {\n\t\tconst {protocol} = new URL(urlString);\n\t\treturn protocol.endsWith(':') && !supportedProtocols.has(protocol);\n\t} catch {\n\t\treturn false;\n\t}\n};\n\nconst normalizeDataURL = (urlString, {stripHash}) => {\n\tconst match = /^data:(?<type>[^,]*?),(?<data>[^#]*?)(?:#(?<hash>.*))?$/.exec(urlString);\n\n\tif (!match) {\n\t\tthrow new Error(`Invalid URL: ${urlString}`);\n\t}\n\n\tlet {type, data, hash} = match.groups;\n\tconst mediaType = type.split(';');\n\thash = stripHash ? '' : hash;\n\n\tlet isBase64 = false;\n\tif (mediaType[mediaType.length - 1] === 'base64') {\n\t\tmediaType.pop();\n\t\tisBase64 = true;\n\t}\n\n\t// Lowercase MIME type\n\tconst mimeType = mediaType.shift()?.toLowerCase() ?? '';\n\tconst attributes = mediaType\n\t\t.map(attribute => {\n\t\t\tlet [key, value = ''] = attribute.split('=').map(string => string.trim());\n\n\t\t\t// Lowercase `charset`\n\t\t\tif (key === 'charset') {\n\t\t\t\tvalue = value.toLowerCase();\n\n\t\t\t\tif (value === DATA_URL_DEFAULT_CHARSET) {\n\t\t\t\t\treturn '';\n\t\t\t\t}\n\t\t\t}\n\n\t\t\treturn `${key}${value ? `=${value}` : ''}`;\n\t\t})\n\t\t.filter(Boolean);\n\n\tconst normalizedMediaType = [\n\t\t...attributes,\n\t];\n\n\tif (isBase64) {\n\t\tnormalizedMediaType.push('base64');\n\t}\n\n\tif (normalizedMediaType.length > 0 || (mimeType && mimeType !== DATA_URL_DEFAULT_MIME_TYPE)) {\n\t\tnormalizedMediaType.unshift(mimeType);\n\t}\n\n\treturn `data:${normalizedMediaType.join(';')},${isBase64 ? data.trim() : data}${hash ? `#${hash}` : ''}`;\n};\n\nexport default function normalizeUrl(urlString, options) {\n\toptions = {\n\t\tdefaultProtocol: 'http',\n\t\tnormalizeProtocol: true,\n\t\tforceHttp: false,\n\t\tforceHttps: false,\n\t\tstripAuthentication: true,\n\t\tstripHash: false,\n\t\tstripTextFragment: true,\n\t\tstripWWW: true,\n\t\tremoveQueryParameters: [/^utm_\\w+/i],\n\t\tremoveTrailingSlash: true,\n\t\tremoveSingleSlash: true,\n\t\tremoveDirectoryIndex: false,\n\t\tremoveExplicitPort: false,\n\t\tsortQueryParameters: true,\n\t\t...options,\n\t};\n\n\t// Legacy: Append `:` to the protocol if missing.\n\tif (typeof options.defaultProtocol === 'string' && !options.defaultProtocol.endsWith(':')) {\n\t\toptions.defaultProtocol = `${options.defaultProtocol}:`;\n\t}\n\n\turlString = urlString.trim();\n\n\t// Data URL\n\tif (/^data:/i.test(urlString)) {\n\t\treturn normalizeDataURL(urlString, options);\n\t}\n\n\tif (hasCustomProtocol(urlString)) {\n\t\treturn urlString;\n\t}\n\n\tconst hasRelativeProtocol = urlString.startsWith('//');\n\tconst isRelativeUrl = !hasRelativeProtocol && /^\\.*\\//.test(urlString);\n\n\t// Prepend protocol\n\tif (!isRelativeUrl) {\n\t\turlString = urlString.replace(/^(?!(?:\\w+:)?\\/\\/)|^\\/\\//, options.defaultProtocol);\n\t}\n\n\tconst urlObject = new URL(urlString);\n\n\tif (options.forceHttp && options.forceHttps) {\n\t\tthrow new Error('The `forceHttp` and `forceHttps` options cannot be used together');\n\t}\n\n\tif (options.forceHttp && urlObject.protocol === 'https:') {\n\t\turlObject.protocol = 'http:';\n\t}\n\n\tif (options.forceHttps && urlObject.protocol === 'http:') {\n\t\turlObject.protocol = 'https:';\n\t}\n\n\t// Remove auth\n\tif (options.stripAuthentication) {\n\t\turlObject.username = '';\n\t\turlObject.password = '';\n\t}\n\n\t// Remove hash\n\tif (options.stripHash) {\n\t\turlObject.hash = '';\n\t} else if (options.stripTextFragment) {\n\t\turlObject.hash = urlObject.hash.replace(/#?:~:text.*?$/i, '');\n\t}\n\n\t// Remove duplicate slashes if not preceded by a protocol\n\t// NOTE: This could be implemented using a single negative lookbehind\n\t// regex, but we avoid that to maintain compatibility with older js engines\n\t// which do not have support for that feature.\n\tif (urlObject.pathname) {\n\t\t// TODO: Replace everything below with `urlObject.pathname = urlObject.pathname.replace(/(?<!\\b[a-z][a-z\\d+\\-.]{1,50}:)\\/{2,}/g, '/');` when Safari supports negative lookbehind.\n\n\t\t// Split the string by occurrences of this protocol regex, and perform\n\t\t// duplicate-slash replacement on the strings between those occurrences\n\t\t// (if any).\n\t\tconst protocolRegex = /\\b[a-z][a-z\\d+\\-.]{1,50}:\\/\\//g;\n\n\t\tlet lastIndex = 0;\n\t\tlet result = '';\n\t\tfor (;;) {\n\t\t\tconst match = protocolRegex.exec(urlObject.pathname);\n\t\t\tif (!match) {\n\t\t\t\tbreak;\n\t\t\t}\n\n\t\t\tconst protocol = match[0];\n\t\t\tconst protocolAtIndex = match.index;\n\t\t\tconst intermediate = urlObject.pathname.slice(lastIndex, protocolAtIndex);\n\n\t\t\tresult += intermediate.replace(/\\/{2,}/g, '/');\n\t\t\tresult += protocol;\n\t\t\tlastIndex = protocolAtIndex + protocol.length;\n\t\t}\n\n\t\tconst remnant = urlObject.pathname.slice(lastIndex, urlObject.pathname.length);\n\t\tresult += remnant.replace(/\\/{2,}/g, '/');\n\n\t\turlObject.pathname = result;\n\t}\n\n\t// Decode URI octets\n\tif (urlObject.pathname) {\n\t\ttry {\n\t\t\turlObject.pathname = decodeURI(urlObject.pathname);\n\t\t} catch {}\n\t}\n\n\t// Remove directory index\n\tif (options.removeDirectoryIndex === true) {\n\t\toptions.removeDirectoryIndex = [/^index\\.[a-z]+$/];\n\t}\n\n\tif (Array.isArray(options.removeDirectoryIndex) && options.removeDirectoryIndex.length > 0) {\n\t\tlet pathComponents = urlObject.pathname.split('/');\n\t\tconst lastComponent = pathComponents[pathComponents.length - 1];\n\n\t\tif (testParameter(lastComponent, options.removeDirectoryIndex)) {\n\t\t\tpathComponents = pathComponents.slice(0, -1);\n\t\t\turlObject.pathname = pathComponents.slice(1).join('/') + '/';\n\t\t}\n\t}\n\n\tif (urlObject.hostname) {\n\t\t// Remove trailing dot\n\t\turlObject.hostname = urlObject.hostname.replace(/\\.$/, '');\n\n\t\t// Remove `www.`\n\t\tif (options.stripWWW && /^www\\.(?!www\\.)[a-z\\-\\d]{1,63}\\.[a-z.\\-\\d]{2,63}$/.test(urlObject.hostname)) {\n\t\t\t// Each label should be max 63 at length (min: 1).\n\t\t\t// Source: https://en.wikipedia.org/wiki/Hostname#Restrictions_on_valid_host_names\n\t\t\t// Each TLD should be up to 63 characters long (min: 2).\n\t\t\t// It is technically possible to have a single character TLD, but none currently exist.\n\t\t\turlObject.hostname = urlObject.hostname.replace(/^www\\./, '');\n\t\t}\n\t}\n\n\t// Remove query unwanted parameters\n\tif (Array.isArray(options.removeQueryParameters)) {\n\t\t// eslint-disable-next-line unicorn/no-useless-spread -- We are intentionally spreading to get a copy.\n\t\tfor (const key of [...urlObject.searchParams.keys()]) {\n\t\t\tif (testParameter(key, options.removeQueryParameters)) {\n\t\t\t\turlObject.searchParams.delete(key);\n\t\t\t}\n\t\t}\n\t}\n\n\tif (!Array.isArray(options.keepQueryParameters) && options.removeQueryParameters === true) {\n\t\turlObject.search = '';\n\t}\n\n\t// Keep wanted query parameters\n\tif (Array.isArray(options.keepQueryParameters) && options.keepQueryParameters.length > 0) {\n\t\t// eslint-disable-next-line unicorn/no-useless-spread -- We are intentionally spreading to get a copy.\n\t\tfor (const key of [...urlObject.searchParams.keys()]) {\n\t\t\tif (!testParameter(key, options.keepQueryParameters)) {\n\t\t\t\turlObject.searchParams.delete(key);\n\t\t\t}\n\t\t}\n\t}\n\n\t// Sort query parameters\n\tif (options.sortQueryParameters) {\n\t\turlObject.searchParams.sort();\n\n\t\t// Calling `.sort()` encodes the search parameters, so we need to decode them again.\n\t\ttry {\n\t\t\turlObject.search = decodeURIComponent(urlObject.search);\n\t\t} catch {}\n\t}\n\n\tif (options.removeTrailingSlash) {\n\t\turlObject.pathname = urlObject.pathname.replace(/\\/$/, '');\n\t}\n\n\t// Remove an explicit port number, excluding a default port number, if applicable\n\tif (options.removeExplicitPort && urlObject.port) {\n\t\turlObject.port = '';\n\t}\n\n\tconst oldUrlString = urlString;\n\n\t// Take advantage of many of the Node `url` normalizations\n\turlString = urlObject.toString();\n\n\tif (!options.removeSingleSlash && urlObject.pathname === '/' && !oldUrlString.endsWith('/') && urlObject.hash === '') {\n\t\turlString = urlString.replace(/\\/$/, '');\n\t}\n\n\t// Remove ending `/` unless removeSingleSlash is false\n\tif ((options.removeTrailingSlash || urlObject.pathname === '/') && urlObject.hash === '' && options.removeSingleSlash) {\n\t\turlString = urlString.replace(/\\/$/, '');\n\t}\n\n\t// Restore relative protocol, if applicable\n\tif (hasRelativeProtocol && !options.normalizeProtocol) {\n\t\turlString = urlString.replace(/^http:\\/\\//, '//');\n\t}\n\n\t// Remove http/https\n\tif (options.stripProtocol) {\n\t\turlString = urlString.replace(/^(?:https?:)?\\/\\//, '');\n\t}\n\n\treturn urlString;\n}\n","import { Logger } from \"./logger\";\n\nexport type ChainPatrolClientOptions = {\n apiKey: string;\n baseUrl?: string;\n};\n\ntype ApiRequest = {\n path: string[];\n method: \"GET\" | \"POST\" | \"PUT\" | \"DELETE\";\n body?: unknown;\n};\n\nexport type AssetType = \"URL\" | \"PAGE\" | \"ADDRESS\";\nexport type AssetStatus = \"ALLOWED\" | \"BLOCKED\" | \"UNKNOWN\";\n\nfunction trimTrailingSlashes(url: string): string {\n return url.replace(/\\/+$/, \"\");\n}\n\nexport class ChainPatrolClient {\n public readonly baseUrl: string;\n private readonly apiKey: string;\n private readonly logger = new Logger({ component: \"ChainPatrolClient\" });\n\n constructor(options: ChainPatrolClientOptions) {\n this.baseUrl = options.baseUrl ?? \"https://app.chainpatrol.io/api/\";\n if (!options.apiKey) {\n throw new Error(\"ChainPatrol API key is required\");\n }\n this.apiKey = options.apiKey;\n }\n\n private async fetch<TResult = unknown>(req: ApiRequest): Promise<TResult> {\n const url = `${trimTrailingSlashes(this.baseUrl)}/${req.path.join(\"/\")}`;\n this.logger.debug(\"fetch\", { url, req });\n const res = await fetch(url, {\n method: req.method,\n headers: {\n \"Content-Type\": \"application/json\",\n \"X-Api-Key\": this.apiKey,\n },\n body: JSON.stringify(req.body),\n });\n if (!res.ok) {\n throw new Error(await res.text());\n }\n return res.json();\n }\n\n public get asset() {\n return {\n check: async (req: {\n type: AssetType;\n content: string;\n }): Promise<{\n /**\n * \"ALLOWED\" - the asset is on the allowlist\n * \"BLOCKED\" - the asset is on the blocklist\n * \"UNKNOWN\" - the asset's status is not known\n */\n status: AssetStatus;\n /**\n * If the asset is allowed or blocked, this will be the reason why.\n * ChainPatrol aggregates data from multiple sources, so this will\n * tell you which source blocked or allowed the asset.\n *\n * ex. 'eth-phishing-detect' - the asset is on MetaMask's blocklist\n * 'reported' - the asset is on ChainPatrol's blocklist because\n * it was reported by a user\n */\n reason?: string;\n }> => {\n return await this.fetch<{\n status: AssetStatus;\n reason?: string;\n }>({\n path: [\"v2\", \"asset\", \"check\"],\n method: \"POST\",\n body: req,\n });\n },\n\n list: async (req: {\n /**\n * Asset type\n */\n type: AssetType;\n /**\n * Status of the assets to retrieve\n */\n status: AssetStatus;\n /**\n * The start date to list assets from. This should be in the format `YYYY-MM-DD` and is inclusive.\n */\n startDate?: string;\n /**\n * The end date to list assets from. This should be in the format `YYYY-MM-DD` and is inclusive.\n */\n endDate?: string;\n }): Promise<\n {\n content: string;\n type: AssetType;\n status: AssetStatus;\n }[]\n > => {\n return await this.fetch<\n {\n content: string;\n type: AssetType;\n status: AssetStatus;\n }[]\n >({\n path: [\"v2\", \"asset\", \"list\"],\n method: \"GET\",\n body: req,\n });\n },\n };\n }\n}\n","export * from \"./extension\";\nexport * from \"./browser\";\nexport * from \"./memory\";\nexport { defineStorage } from \"./define-storage\";\nexport * from \"./types\";\n","import { ThreatDetector } from \"../detector\";\nimport { Storage } from \"./types\";\n\nexport interface Context {\n keys: string[];\n}\n\nexport function defineStorage<T extends Storage>(\n config: (ctx: Context) => T\n): () => T {\n return () =>\n config({\n keys: Object.values(ThreatDetector.StorageKeys),\n });\n}\n","import { defineStorage } from \"./define-storage\";\n\nexport const Extension = defineStorage(({ keys }) => {\n return {\n get: async (key: string) => {\n const result = await chrome.storage.local.get(key);\n return result[key];\n },\n set: async (key: string, value: string) => {\n await chrome.storage.local.set({ [key]: value });\n },\n delete: async (key: string) => {\n await chrome.storage.local.remove(key);\n },\n size: async () => {\n const usageBytes = await chrome.storage.local.getBytesInUse(keys);\n return usageBytes;\n },\n };\n});\n","import { defineStorage } from \"./define-storage\";\n\nfunction isStorageAvailable(type: \"localStorage\" | \"sessionStorage\") {\n let storage;\n try {\n storage = window[type];\n const x = \"__storage_test__\";\n storage.setItem(x, x);\n storage.removeItem(x);\n return true;\n } catch (e) {\n return (\n e instanceof DOMException &&\n // everything except Firefox\n (e.code === 22 ||\n // Firefox\n e.code === 1014 ||\n // test name field too, because code might not be present\n // everything except Firefox\n e.name === \"QuotaExceededError\" ||\n // Firefox\n e.name === \"NS_ERROR_DOM_QUOTA_REACHED\") &&\n // acknowledge QuotaExceededError only if there's something already stored\n storage &&\n storage.length !== 0\n );\n }\n}\n\nexport const Browser = defineStorage(({ keys }) => {\n if (!isStorageAvailable(\"localStorage\")) {\n throw new Error(\"localStorage is not available\");\n }\n\n return {\n get: async (key: string) => {\n return localStorage.getItem(key);\n },\n set: async (key: string, value: string) => {\n localStorage.setItem(key, value);\n },\n delete: async (key: string) => {\n localStorage.removeItem(key);\n },\n size: async () => {\n let total = 0;\n for (let i = 0; i < localStorage.length; i++) {\n const key = localStorage.key(i);\n if (key && keys.includes(key)) {\n total += localStorage.getItem(key)?.length ?? 0;\n }\n }\n return total;\n },\n };\n});\n","import { defineStorage } from \"./define-storage\";\n\nexport const Memory = defineStorage(() => {\n const storage = new Map<string, string>();\n return {\n get: async (key: string) => {\n return storage.get(key) || null;\n },\n set: async (key: string, value: string) => {\n storage.set(key, value);\n },\n delete: async (key: string) => {\n storage.delete(key);\n },\n size: async () => {\n let total = 0;\n for (const value of storage.values()) {\n total += value.length;\n }\n return total;\n },\n };\n});\n"]}
|
|
1
|
+
{"version":3,"sources":["../src/events.ts","../src/logger.ts","../src/relay.ts","../src/detector.ts","../../../node_modules/normalize-url/index.js","../src/client.ts","../src/storage/index.ts","../src/storage/define-storage.ts","../src/storage/extension.ts","../src/storage/browser.ts","../src/storage/memory.ts"],"names":["LogLevel","list"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA,IAAM,oBAAoB;AAC1B,IAAM,oBAAoB;AAC1B,IAAM,kBAAkB;AAEjB,IAAM,SAAS;AAAA,EACpB;AAAA,EACA;AAAA,EACA;AACF;;;ACRO,IAAK,WAAL,kBAAKA,cAAL;AACL,EAAAA,oBAAA;AACA,EAAAA,oBAAA;AACA,EAAAA,oBAAA;AACA,EAAAA,oBAAA;AACA,EAAAA,oBAAA;AALU,SAAAA;AAAA,GAAA;AAQL,IAAM,SAAN,MAAM,QAAO;AAAA,EAIlB,YACE,MACA,WAAqB,cACrB;AANF,SAAQ,OAAgC,CAAC;AAOvC,QAAI,MAAM;AACR,WAAK,OAAO;AAAA,IACd;AACA,SAAK,WAAW;AAAA,EAClB;AAAA,EAEO,KAAK,QAAiC;AAC3C,WAAO,IAAI,QAAO,kCAAK,KAAK,OAAS,SAAU,KAAK,QAAQ;AAAA,EAC9D;AAAA,EAEO,MAAM,SAAiB,QAAkC;AAC9D,SAAK,IAAI,eAAgB,SAAS,MAAM;AAAA,EAC1C;AAAA,EAEO,KAAK,SAAiB,QAAkC;AAC7D,SAAK,IAAI,cAAe,SAAS,MAAM;AAAA,EACzC;AAAA,EAEO,KAAK,SAAiB,QAAkC;AAC7D,SAAK,IAAI,cAAe,SAAS,MAAM;AAAA,EACzC;AAAA,EAEO,MAAM,SAAiB,QAAkC;AAC9D,SAAK,IAAI,eAAgB,SAAS,MAAM;AAAA,EAC1C;AAAA,EAEQ,IACN,OACA,SACA,QACA;AACA,QAAI,QAAQ,KAAK,UAAU;AACzB;AAAA,IACF;AAEA,UAAM,SAAS,iBAAE,SAAS,MAAM,mBAAK,WAAa,KAAK;AACvD,UAAM,YAAY,KAAK,UAAU,QAAQ,MAAM,CAAC;AAChD,YAAQ,IAAI,IAAI,SAAS,KAAK,EAAE,YAAY,MAAM,WAAW;AAAA,EAC/D;AACF;;;AC3CA,SAAS,sBAA6C;AAZtD;AAaE,OAAK,gBAAmB,YAAnB,mBAA4B,SAAS;AACxC,WAAQ,WAAmB,QAAQ;AAAA,EACrC;AACA,OAAI,gBAAW,WAAX,mBAAmB,SAAS;AAC9B,WAAO,WAAW,OAAO;AAAA,EAC3B;AACA,QAAM,IAAI,MAAM,4BAA4B;AAC9C;AAEA,SAAS,kBAAkB;AAtB3B;AAuBE,SACE,CAAC,GAAE,gBAAmB,YAAnB,mBAA4B,YAC/B,CAAC,GAAE,gBAAmB,WAAnB,mBAA2B;AAElC;AAEA,SAAS,kBAAkB;AACzB,SAAO,gBAAgB,KAAK,cAAc;AAC5C;AAEA,SAAS,qBAAqB;AAC5B,SAAO,gBAAgB,KAAK,CAAC,cAAc;AAC7C;AAEA,SAAS,gBAAgB;AACvB,SAAO,CAAC,CAAE,WAAmB;AAC/B;AAQA,SAAS,4BAAoC;AAC3C,QAAM,UAAU,oBAAoB;AACpC,SAAO;AAAA,IACL,aAAa,CAAC,aAAqC;AACjD,cAAQ,UAAU,YAAY,QAAQ;AAAA,IACxC;AAAA,IACA,gBAAgB,CAAC,aAAqC;AACpD,cAAQ,UAAU,eAAe,QAAQ;AAAA,IAC3C;AAAA,IACA,aAAa,CAAO,YAAiB;AACnC,YAAM,CAAC,GAAG,IAAI,MAAM,WAAW,OAAO,KAAK,MAAM;AAAA,QAC/C,QAAQ;AAAA,QACR,mBAAmB;AAAA,MACrB,CAAC;AACD,UAAI,CAAC,IAAI,MAAM,IAAI,OAAO,WAAW,OAAO,KAAK,aAAa;AAC5D,gBAAQ,MAAM,qBAAqB;AACnC;AAAA,MACF;AACA,iBAAW,OAAO,KAAK,YAAY,IAAI,IAAI,OAAO;AAAA,IACpD;AAAA,EACF;AACF;AAEA,SAAS,yBAAiC;AACxC,QAAM,UAAU,oBAAoB;AACpC,SAAO;AAAA,IACL,aAAa,CAAC,aAAqC;AACjD,cAAQ,UAAU,YAAY,QAAQ;AAAA,IACxC;AAAA,IACA,gBAAgB,CAAC,aAAqC;AACpD,cAAQ,UAAU,eAAe,QAAQ;AAAA,IAC3C;AAAA,IACA,aAAa,CAAO,YAAiB;AACnC,cAAQ,YAAY,OAAO,EAAE,MAAM,CAAC,UAAU;AAC5C,gBAAQ,MAAM,0BAA0B,EAAE,SAAS,MAAM,CAAC;AAAA,MAC5D,CAAC;AAAA,IACH;AAAA,EACF;AACF;AAEA,SAAS,mBAA2B;AAClC,SAAO;AAAA,IACL,aAAa,CAAC,aAAqC;AACjD,iBAAW,OAAO,iBAAiB,WAAW,CAAC,UAAU;AACvD,YAAI,MAAM,WAAW,WAAW,QAAQ;AACtC;AAAA,QACF;AACA,iBAAS,MAAM,IAAI;AAAA,MACrB,CAAC;AAAA,IACH;AAAA,IACA,gBAAgB,CAAC,aAAqC;AACpD,iBAAW,OAAO,oBAAoB,WAAW,QAAQ;AAAA,IAC3D;AAAA,IACA,aAAa,CAAC,YAAiB;AAC7B,iBAAW,OAAO,YAAY,SAAS,GAAG;AAAA,IAC5C;AAAA,EACF;AACF;AAaO,IAAM,SAAN,MAAM,OAAM;AAAA,EAkBjB,OAAc,KACZ,MACA,MACA;AACA,UAAM,UAAU;AAAA,MACd;AAAA,MACA;AAAA,MACA,OAAO;AAAA,QACL,IAAI,KAAK,OAAO,EAAE,SAAS,EAAE,EAAE,UAAU,GAAG,CAAC;AAAA,QAC7C,QAAQ,WAAW,SAAS;AAAA,MAC9B;AAAA,IACF;AAEA,WAAM,OAAO,MAAM,mBAAmB,OAAO;AAE7C,eAAW,UAAU,OAAM,SAAS;AAClC,aAAO,YAAY,OAAO;AAAA,IAC5B;AAAA,EACF;AAAA,EAEA,OAAc,IAAI,QAA6B;AAC7C,UAAM,YAAY,oBAAI,IAA4B;AAElD,eAAW,UAAU,OAAM,SAAS;AAClC,YAAM,WAAW,OAAM,cAAc,KAAK,MAAM,QAAQ,MAAM;AAC9D,gBAAU,IAAI,QAAQ;AACtB,aAAO,YAAY,QAAQ;AAAA,IAC7B;AAEA,WAAM,OAAO,MAAM,iBAAiB,EAAE,OAAO,CAAC;AAE9C,WAAO,MAAM;AACX,iBAAW,UAAU,OAAM,SAAS;AAClC,mBAAW,YAAY,WAAW;AAChC,iBAAO,eAAe,QAAQ;AAAA,QAChC;AAAA,MACF;AAEA,aAAM,OAAO,MAAM,iBAAiB,EAAE,OAAO,CAAC;AAAA,IAChD;AAAA,EACF;AAAA,EAEA,OAAe,cACb,cACA,QACA,SACA;AACA,QAAI,CAAC,OAAO,SAAS,QAAQ,IAAI,GAAG;AAClC,aAAM,OAAO,MAAM,oBAAoB,EAAE,QAAQ,CAAC;AAClD;AAAA,IACF;AAEA,UAAM,qBAAqB,OAAM,QAAQ;AAAA,MACvC,CAAC,WAAW,WAAW;AAAA,IACzB;AAEA,eAAW,qBAAqB,oBAAoB;AAClD,wBAAkB,YAAY,OAAO;AAAA,IACvC;AAAA,EACF;AAAA,EAEA,OAAc,GACZ,aACA,UACA;AACA,UAAM,YAAY,oBAAI,IAA4B;AAClD,eAAW,UAAU,OAAM,SAAS;AAClC,YAAM,WAAW,CAAC,YAAiB;AACjC,YAAI,QAAQ,SAAS,aAAa;AAChC,iBAAM,OAAO,MAAM,oBAAoB,EAAE,QAAQ,CAAC;AAClD;AAAA,QACF;AACA,iBAAS,QAAQ,IAAI;AAAA,MACvB;AACA,gBAAU,IAAI,QAAQ;AACtB,aAAO,YAAY,QAAQ;AAAA,IAC7B;AAEA,WAAO,MAAM;AACX,iBAAW,UAAU,OAAM,SAAS;AAClC,mBAAW,YAAY,WAAW;AAChC,iBAAO,eAAe,QAAQ;AAAA,QAChC;AAAA,MACF;AAAA,IACF;AAAA,EACF;AACF;AAxGa,OACM,UAAoB,CAAC;AAD3B,OAEa,SAAS,IAAI,OAAO,EAAE,WAAW,QAAQ,CAAC;AAAA,CAElE,MAAO;AACL,MAAI,mBAAmB,GAAG;AACxB,WAAM,OAAO,KAAK,4BAA4B;AAC9C,WAAM,QAAQ,KAAK,0BAA0B,CAAC;AAAA,EAChD,WAAW,gBAAgB,GAAG;AAC5B,WAAM,OAAO,KAAK,yBAAyB;AAC3C,WAAM,QAAQ,KAAK,uBAAuB,CAAC;AAC3C,WAAM,QAAQ,KAAK,iBAAiB,CAAC;AAAA,EACvC,WAAW,cAAc,GAAG;AAC1B,WAAM,OAAO,KAAK,uBAAuB;AACzC,WAAM,QAAQ,KAAK,iBAAiB,CAAC;AAAA,EACvC;AACF;AAhBK,IAAM,QAAN;;;ACrHP,SAAS,SAAS,mBAAmB;;;ACCrC,IAAM,6BAA6B;AACnC,IAAM,2BAA2B;AAEjC,IAAM,gBAAgB,CAAC,MAAM,YAAY,QAAQ,KAAK,YAAU,kBAAkB,SAAS,OAAO,KAAK,IAAI,IAAI,WAAW,IAAI;AAE9H,IAAM,qBAAqB,oBAAI,IAAI;AAAA,EAClC;AAAA,EACA;AAAA,EACA;AACD,CAAC;AAED,IAAM,oBAAoB,eAAa;AACtC,MAAI;AACH,UAAM,EAAC,SAAQ,IAAI,IAAI,IAAI,SAAS;AACpC,WAAO,SAAS,SAAS,GAAG,KAAK,CAAC,mBAAmB,IAAI,QAAQ;AAAA,EAClE,SAAQ,GAAN;AACD,WAAO;AAAA,EACR;AACD;AAEA,IAAM,mBAAmB,CAAC,WAAW,EAAC,UAAS,MAAM;AArBrD;AAsBC,QAAM,QAAQ,WAAC,yDAAwD,EAAC,KAAK,SAAS;AAEtF,MAAI,CAAC,OAAO;AACX,UAAM,IAAI,MAAM,gBAAgB,WAAW;AAAA,EAC5C;AAEA,MAAI,EAAC,MAAM,MAAM,KAAI,IAAI,MAAM;AAC/B,QAAM,YAAY,KAAK,MAAM,GAAG;AAChC,SAAO,YAAY,KAAK;AAExB,MAAI,WAAW;AACf,MAAI,UAAU,UAAU,SAAS,CAAC,MAAM,UAAU;AACjD,cAAU,IAAI;AACd,eAAW;AAAA,EACZ;AAGA,QAAM,YAAW,qBAAU,MAAM,MAAhB,mBAAmB,kBAAnB,YAAoC;AACrD,QAAM,aAAa,UACjB,IAAI,eAAa;AACjB,QAAI,CAAC,KAAK,QAAQ,EAAE,IAAI,UAAU,MAAM,GAAG,EAAE,IAAI,YAAU,OAAO,KAAK,CAAC;AAGxE,QAAI,QAAQ,WAAW;AACtB,cAAQ,MAAM,YAAY;AAE1B,UAAI,UAAU,0BAA0B;AACvC,eAAO;AAAA,MACR;AAAA,IACD;AAEA,WAAO,GAAG,MAAM,QAAQ,IAAI,UAAU;AAAA,EACvC,CAAC,EACA,OAAO,OAAO;AAEhB,QAAM,sBAAsB;AAAA,IAC3B,GAAG;AAAA,EACJ;AAEA,MAAI,UAAU;AACb,wBAAoB,KAAK,QAAQ;AAAA,EAClC;AAEA,MAAI,oBAAoB,SAAS,KAAM,YAAY,aAAa,4BAA6B;AAC5F,wBAAoB,QAAQ,QAAQ;AAAA,EACrC;AAEA,SAAO,QAAQ,oBAAoB,KAAK,GAAG,KAAK,WAAW,KAAK,KAAK,IAAI,OAAO,OAAO,IAAI,SAAS;AACrG;AAEe,SAAR,aAA8B,WAAW,SAAS;AACxD,YAAU;AAAA,IACT,iBAAiB;AAAA,IACjB,mBAAmB;AAAA,IACnB,WAAW;AAAA,IACX,YAAY;AAAA,IACZ,qBAAqB;AAAA,IACrB,WAAW;AAAA,IACX,mBAAmB;AAAA,IACnB,UAAU;AAAA,IACV,uBAAuB,CAAC,WAAW;AAAA,IACnC,qBAAqB;AAAA,IACrB,mBAAmB;AAAA,IACnB,sBAAsB;AAAA,IACtB,oBAAoB;AAAA,IACpB,qBAAqB;AAAA,KAClB;AAIJ,MAAI,OAAO,QAAQ,oBAAoB,YAAY,CAAC,QAAQ,gBAAgB,SAAS,GAAG,GAAG;AAC1F,YAAQ,kBAAkB,GAAG,QAAQ;AAAA,EACtC;AAEA,cAAY,UAAU,KAAK;AAG3B,MAAI,UAAU,KAAK,SAAS,GAAG;AAC9B,WAAO,iBAAiB,WAAW,OAAO;AAAA,EAC3C;AAEA,MAAI,kBAAkB,SAAS,GAAG;AACjC,WAAO;AAAA,EACR;AAEA,QAAM,sBAAsB,UAAU,WAAW,IAAI;AACrD,QAAM,gBAAgB,CAAC,uBAAuB,SAAS,KAAK,SAAS;AAGrE,MAAI,CAAC,eAAe;AACnB,gBAAY,UAAU,QAAQ,4BAA4B,QAAQ,eAAe;AAAA,EAClF;AAEA,QAAM,YAAY,IAAI,IAAI,SAAS;AAEnC,MAAI,QAAQ,aAAa,QAAQ,YAAY;AAC5C,UAAM,IAAI,MAAM,kEAAkE;AAAA,EACnF;AAEA,MAAI,QAAQ,aAAa,UAAU,aAAa,UAAU;AACzD,cAAU,WAAW;AAAA,EACtB;AAEA,MAAI,QAAQ,cAAc,UAAU,aAAa,SAAS;AACzD,cAAU,WAAW;AAAA,EACtB;AAGA,MAAI,QAAQ,qBAAqB;AAChC,cAAU,WAAW;AACrB,cAAU,WAAW;AAAA,EACtB;AAGA,MAAI,QAAQ,WAAW;AACtB,cAAU,OAAO;AAAA,EAClB,WAAW,QAAQ,mBAAmB;AACrC,cAAU,OAAO,UAAU,KAAK,QAAQ,kBAAkB,EAAE;AAAA,EAC7D;AAMA,MAAI,UAAU,UAAU;AAMvB,UAAM,gBAAgB;AAEtB,QAAI,YAAY;AAChB,QAAI,SAAS;AACb,eAAS;AACR,YAAM,QAAQ,cAAc,KAAK,UAAU,QAAQ;AACnD,UAAI,CAAC,OAAO;AACX;AAAA,MACD;AAEA,YAAM,WAAW,MAAM,CAAC;AACxB,YAAM,kBAAkB,MAAM;AAC9B,YAAM,eAAe,UAAU,SAAS,MAAM,WAAW,eAAe;AAExE,gBAAU,aAAa,QAAQ,WAAW,GAAG;AAC7C,gBAAU;AACV,kBAAY,kBAAkB,SAAS;AAAA,IACxC;AAEA,UAAM,UAAU,UAAU,SAAS,MAAM,WAAW,UAAU,SAAS,MAAM;AAC7E,cAAU,QAAQ,QAAQ,WAAW,GAAG;AAExC,cAAU,WAAW;AAAA,EACtB;AAGA,MAAI,UAAU,UAAU;AACvB,QAAI;AACH,gBAAU,WAAW,UAAU,UAAU,QAAQ;AAAA,IAClD,SAAQ,GAAN;AAAA,IAAO;AAAA,EACV;AAGA,MAAI,QAAQ,yBAAyB,MAAM;AAC1C,YAAQ,uBAAuB,CAAC,iBAAiB;AAAA,EAClD;AAEA,MAAI,MAAM,QAAQ,QAAQ,oBAAoB,KAAK,QAAQ,qBAAqB,SAAS,GAAG;AAC3F,QAAI,iBAAiB,UAAU,SAAS,MAAM,GAAG;AACjD,UAAM,gBAAgB,eAAe,eAAe,SAAS,CAAC;AAE9D,QAAI,cAAc,eAAe,QAAQ,oBAAoB,GAAG;AAC/D,uBAAiB,eAAe,MAAM,GAAG,EAAE;AAC3C,gBAAU,WAAW,eAAe,MAAM,CAAC,EAAE,KAAK,GAAG,IAAI;AAAA,IAC1D;AAAA,EACD;AAEA,MAAI,UAAU,UAAU;AAEvB,cAAU,WAAW,UAAU,SAAS,QAAQ,OAAO,EAAE;AAGzD,QAAI,QAAQ,YAAY,oDAAoD,KAAK,UAAU,QAAQ,GAAG;AAKrG,gBAAU,WAAW,UAAU,SAAS,QAAQ,UAAU,EAAE;AAAA,IAC7D;AAAA,EACD;AAGA,MAAI,MAAM,QAAQ,QAAQ,qBAAqB,GAAG;AAEjD,eAAW,OAAO,CAAC,GAAG,UAAU,aAAa,KAAK,CAAC,GAAG;AACrD,UAAI,cAAc,KAAK,QAAQ,qBAAqB,GAAG;AACtD,kBAAU,aAAa,OAAO,GAAG;AAAA,MAClC;AAAA,IACD;AAAA,EACD;AAEA,MAAI,CAAC,MAAM,QAAQ,QAAQ,mBAAmB,KAAK,QAAQ,0BAA0B,MAAM;AAC1F,cAAU,SAAS;AAAA,EACpB;AAGA,MAAI,MAAM,QAAQ,QAAQ,mBAAmB,KAAK,QAAQ,oBAAoB,SAAS,GAAG;AAEzF,eAAW,OAAO,CAAC,GAAG,UAAU,aAAa,KAAK,CAAC,GAAG;AACrD,UAAI,CAAC,cAAc,KAAK,QAAQ,mBAAmB,GAAG;AACrD,kBAAU,aAAa,OAAO,GAAG;AAAA,MAClC;AAAA,IACD;AAAA,EACD;AAGA,MAAI,QAAQ,qBAAqB;AAChC,cAAU,aAAa,KAAK;AAG5B,QAAI;AACH,gBAAU,SAAS,mBAAmB,UAAU,MAAM;AAAA,IACvD,SAAQ,GAAN;AAAA,IAAO;AAAA,EACV;AAEA,MAAI,QAAQ,qBAAqB;AAChC,cAAU,WAAW,UAAU,SAAS,QAAQ,OAAO,EAAE;AAAA,EAC1D;AAGA,MAAI,QAAQ,sBAAsB,UAAU,MAAM;AACjD,cAAU,OAAO;AAAA,EAClB;AAEA,QAAM,eAAe;AAGrB,cAAY,UAAU,SAAS;AAE/B,MAAI,CAAC,QAAQ,qBAAqB,UAAU,aAAa,OAAO,CAAC,aAAa,SAAS,GAAG,KAAK,UAAU,SAAS,IAAI;AACrH,gBAAY,UAAU,QAAQ,OAAO,EAAE;AAAA,EACxC;AAGA,OAAK,QAAQ,uBAAuB,UAAU,aAAa,QAAQ,UAAU,SAAS,MAAM,QAAQ,mBAAmB;AACtH,gBAAY,UAAU,QAAQ,OAAO,EAAE;AAAA,EACxC;AAGA,MAAI,uBAAuB,CAAC,QAAQ,mBAAmB;AACtD,gBAAY,UAAU,QAAQ,cAAc,IAAI;AAAA,EACjD;AAGA,MAAI,QAAQ,eAAe;AAC1B,gBAAY,UAAU,QAAQ,qBAAqB,EAAE;AAAA,EACtD;AAEA,SAAO;AACR;;;ADvRA,SAAS,SAAS;;;AEclB,SAAS,oBAAoB,KAAqB;AAChD,SAAO,IAAI,QAAQ,QAAQ,EAAE;AAC/B;AAEO,IAAM,oBAAN,MAAwB;AAAA,EAK7B,YAAY,SAAmC;AAF/C,SAAiB,SAAS,IAAI,OAAO,EAAE,WAAW,oBAAoB,CAAC;AAvBzE;AA0BI,SAAK,WAAU,aAAQ,YAAR,YAAmB;AAClC,QAAI,CAAC,QAAQ,QAAQ;AACnB,YAAM,IAAI,MAAM,iCAAiC;AAAA,IACnD;AACA,SAAK,SAAS,QAAQ;AAAA,EACxB;AAAA,EAEc,MAAyB,KAAmC;AAAA;AACxE,YAAM,MAAM,GAAG,oBAAoB,KAAK,OAAO,KAAK,IAAI,KAAK,KAAK,GAAG;AACrE,WAAK,OAAO,MAAM,SAAS,EAAE,KAAK,IAAI,CAAC;AACvC,YAAM,MAAM,MAAM,MAAM,KAAK;AAAA,QAC3B,QAAQ,IAAI;AAAA,QACZ,SAAS;AAAA,UACP,gBAAgB;AAAA,UAChB,aAAa,KAAK;AAAA,QACpB;AAAA,QACA,MAAM,KAAK,UAAU,IAAI,IAAI;AAAA,MAC/B,CAAC;AACD,UAAI,CAAC,IAAI,IAAI;AACX,cAAM,IAAI,MAAM,MAAM,IAAI,KAAK,CAAC;AAAA,MAClC;AACA,aAAO,IAAI,KAAK;AAAA,IAClB;AAAA;AAAA,EAEA,IAAW,QAAQ;AACjB,WAAO;AAAA,MACL,OAAO,CAAO,QAoBR;AACJ,eAAO,MAAM,KAAK,MAGf;AAAA,UACD,MAAM,CAAC,MAAM,SAAS,OAAO;AAAA,UAC7B,QAAQ;AAAA,UACR,MAAM;AAAA,QACR,CAAC;AAAA,MACH;AAAA,MAEA,MAAM,CAAO,QAuBR;AACH,eAAO,MAAM,KAAK,MAMhB;AAAA,UACA,MAAM,CAAC,MAAM,SAAS,MAAM;AAAA,UAC5B,QAAQ;AAAA,UACR,MAAM;AAAA,QACR,CAAC;AAAA,MACH;AAAA,IACF;AAAA,EACF;AAAA,EAEA,IAAW,SAAS;AAClB,WAAO;AAAA,MACL,QAAQ,CAAO,QA+BT;AACJ,eAAO,MAAM,KAAK,MAQf;AAAA,UACD,MAAM,CAAC,MAAM,UAAU,QAAQ;AAAA,UAC/B,QAAQ;AAAA,UACR,MAAM;AAAA,QACR,CAAC;AAAA,MACH;AAAA,IACF;AAAA,EACF;AACF;;;AC5KA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;;ACOO,SAAS,cACd,QACS;AACT,SAAO,MACL,OAAO;AAAA,IACL,MAAM,OAAO,OAAO,eAAe,WAAW;AAAA,EAChD,CAAC;AACL;;;ACZO,IAAM,YAAY,cAAc,CAAC,EAAE,KAAK,MAAM;AACnD,SAAO;AAAA,IACL,KAAK,CAAO,QAAgB;AAC1B,YAAM,SAAS,MAAM,OAAO,QAAQ,MAAM,IAAI,GAAG;AACjD,aAAO,OAAO,GAAG;AAAA,IACnB;AAAA,IACA,KAAK,CAAO,KAAa,UAAkB;AACzC,YAAM,OAAO,QAAQ,MAAM,IAAI,EAAE,CAAC,GAAG,GAAG,MAAM,CAAC;AAAA,IACjD;AAAA,IACA,QAAQ,CAAO,QAAgB;AAC7B,YAAM,OAAO,QAAQ,MAAM,OAAO,GAAG;AAAA,IACvC;AAAA,IACA,MAAM,MAAY;AAChB,YAAM,aAAa,MAAM,OAAO,QAAQ,MAAM,cAAc,IAAI;AAChE,aAAO;AAAA,IACT;AAAA,EACF;AACF,CAAC;;;ACjBD,SAAS,mBAAmB,MAAyC;AACnE,MAAI;AACJ,MAAI;AACF,cAAU,OAAO,IAAI;AACrB,UAAM,IAAI;AACV,YAAQ,QAAQ,GAAG,CAAC;AACpB,YAAQ,WAAW,CAAC;AACpB,WAAO;AAAA,EACT,SAAS,GAAP;AACA,WACE,aAAa;AAAA,KAEZ,EAAE,SAAS;AAAA,IAEV,EAAE,SAAS;AAAA;AAAA,IAGX,EAAE,SAAS;AAAA,IAEX,EAAE,SAAS;AAAA,IAEb,WACA,QAAQ,WAAW;AAAA,EAEvB;AACF;AAEO,IAAM,UAAU,cAAc,CAAC,EAAE,KAAK,MAAM;AACjD,MAAI,CAAC,mBAAmB,cAAc,GAAG;AACvC,UAAM,IAAI,MAAM,+BAA+B;AAAA,EACjD;AAEA,SAAO;AAAA,IACL,KAAK,CAAO,QAAgB;AAC1B,aAAO,aAAa,QAAQ,GAAG;AAAA,IACjC;AAAA,IACA,KAAK,CAAO,KAAa,UAAkB;AACzC,mBAAa,QAAQ,KAAK,KAAK;AAAA,IACjC;AAAA,IACA,QAAQ,CAAO,QAAgB;AAC7B,mBAAa,WAAW,GAAG;AAAA,IAC7B;AAAA,IACA,MAAM,MAAY;AA5CtB;AA6CM,UAAI,QAAQ;AACZ,eAAS,IAAI,GAAG,IAAI,aAAa,QAAQ,KAAK;AAC5C,cAAM,MAAM,aAAa,IAAI,CAAC;AAC9B,YAAI,OAAO,KAAK,SAAS,GAAG,GAAG;AAC7B,oBAAS,wBAAa,QAAQ,GAAG,MAAxB,mBAA2B,WAA3B,YAAqC;AAAA,QAChD;AAAA,MACF;AACA,aAAO;AAAA,IACT;AAAA,EACF;AACF,CAAC;;;ACrDM,IAAM,SAAS,cAAc,MAAM;AACxC,QAAM,UAAU,oBAAI,IAAoB;AACxC,SAAO;AAAA,IACL,KAAK,CAAO,QAAgB;AAC1B,aAAO,QAAQ,IAAI,GAAG,KAAK;AAAA,IAC7B;AAAA,IACA,KAAK,CAAO,KAAa,UAAkB;AACzC,cAAQ,IAAI,KAAK,KAAK;AAAA,IACxB;AAAA,IACA,QAAQ,CAAO,QAAgB;AAC7B,cAAQ,OAAO,GAAG;AAAA,IACpB;AAAA,IACA,MAAM,MAAY;AAChB,UAAI,QAAQ;AACZ,iBAAW,SAAS,QAAQ,OAAO,GAAG;AACpC,iBAAS,MAAM;AAAA,MACjB;AACA,aAAO;AAAA,IACT;AAAA,EACF;AACF,CAAC;;;APSM,IAAM,mBAAN,cAA+B,MAAM;AAAA,EAC1C,YAAY,SAAiB;AAC3B,UAAM,OAAO;AACb,SAAK,OAAO;AAAA,EACd;AACF;AAEO,IAAM,kBAAN,MAAM,gBAAe;AAAA,EA0D1B,YAAY;AAAA,IACV,OAAO;AAAA,IACP,SAAS;AAAA,IACT,UAAU,OAAO;AAAA,IACjB;AAAA,IACA;AAAA,EACF,GAMG;AAlDH,SAAiB,SAAS,IAAI,OAAO,EAAE,WAAW,iBAAiB,CAAC;AAmDlE,SAAK,OAAO;AACZ,SAAK,UAAU;AACf,SAAK,cAAc,oCAAe,gBAAe;AACjD,QAAI,SAAS,SAAS;AACpB,WAAK,SAAS,IAAI,kBAAkB;AAAA,QAClC;AAAA,QACA,SAAS;AAAA,MACX,CAAC;AAAA,IACH;AAAA,EACF;AAAA,EAEa,IAAI,KAAiC;AAAA;AAChD,WAAK,OAAO,MAAM,gBAAgB,EAAE,IAAI,CAAC;AAEzC,UAAI;AACJ,UAAI;AACF,kBAAU,KAAK,gBAAgB,GAAG;AAAA,MACpC,SAAS,GAAP;AACA,aAAK,OAAO,MAAM,0BAA0B,EAAE,KAAK,OAAO,EAAE,CAAC;AAC7D,eAAO;AAAA,UACL,IAAI;AAAA,UACJ;AAAA,UACA,OACE,aAAa,mBAAmB,EAAE,UAAU;AAAA,QAChD;AAAA,MACF;AAEA,WAAK,OAAO,MAAM,qBAAqB,EAAE,QAAQ,CAAC;AAElD,UAAI,WACF,MAAM,QAAQ,IAAI,QAAQ,IAAI,CAAC,WAAW,KAAK,UAAU,QAAQ,GAAG,CAAC,CAAC,GACtE;AAAA,QACA,CAAsB,MACpB,EAAE;AAAA,MACN;AAEA,UAAI,QAAQ,WAAW,GAAG;AACxB,eAAO;AAAA,UACL,IAAI;AAAA,UACJ;AAAA,UACA,OAAO;AAAA,QACT;AAAA,MACF;AAEA,WAAK,OAAO,MAAM,uBAAuB,EAAE,QAAQ,CAAC;AAEpD,UAAI,QAAQ,KAAK,CAAC,MAAM,EAAE,WAAW,SAAS,GAAG;AAC/C,eAAO;AAAA,UACL,IAAI;AAAA,UACJ,QAAQ;AAAA,UACR;AAAA,QACF;AAAA,MACF;AAEA,iBAAW,UAAU,SAAS;AAC5B,YAAI,OAAO,MAAM,OAAO,WAAW,WAAW;AAC5C,iBAAO;AAAA,QACT;AAAA,MACF;AAEA,aAAO,QAAQ,CAAC;AAAA,IAClB;AAAA;AAAA,EAEQ,gBAAgB,MAAwB;AA5KlD;AA6KI,UAAM,SAAS,KAAK,mBAAmB,IAAI;AAE3C,UAAM,UAAU,CAAC,MAAM;AAEvB,UAAM,eAAe,YAAY,MAAM;AACvC,QAAI,CAAC,aAAa,WAAW;AAC3B,aAAO;AAAA,IACT;AAEA,UAAM,kBAAiB,wBAAa,cAAb,mBAAwB,MAAM,SAA9B,YAAsC,CAAC;AAE9D,aAAS,IAAI,GAAG,IAAI,eAAe,QAAQ,KAAK;AAC9C,YAAM,YAAY,eAAe,MAAM,CAAC,EAAE,KAAK,GAAG;AAClD,cAAQ,QAAQ,GAAG,aAAa,QAAkB;AAAA,IACpD;AAEA,WAAO;AAAA,EACT;AAAA,EAEc,UAAU,QAAgB,KAAiC;AAAA;AACvE,UAAI,SAAS,MAAM,KAAK,mBAAmB,MAAM;AAEjD,UAAI,KAAK,SAAS,WAAW,KAAK,UAAU,WAAW,WAAW;AAChE,YAAI;AACF,gBAAM,MAAM,MAAM,KAAK,OAAO,MAAM,MAAM;AAAA,YACxC,MAAM;AAAA,YACN,SAAS;AAAA,UACX,CAAC;AAGD,eAAK,OAAO,MAAM,kBAAkB,EAAE,QAAQ,QAAQ,IAAI,OAAO,CAAC;AAClE,cAAI,IAAI,WAAW,WAAW;AAC5B,iBAAK,iBAAiB,QAAQ,gBAAe,YAAY,SAAS;AAAA,UACpE,WAAW,IAAI,WAAW,WAAW;AACnC,iBAAK,iBAAiB,QAAQ,gBAAe,YAAY,SAAS;AAAA,UACpE;AAEA,mBAAS,IAAI;AAAA,QACf,SAAS,GAAP;AACA,iBAAO;AAAA,YACL,IAAI;AAAA,YACJ,KAAK;AAAA,YACL,OAAO;AAAA,UACT;AAAA,QACF;AAAA,MACF;AAEA,UAAI;AAEJ,UAAI,WAAW,WAAW;AACxB,YAAI,OAAO,KAAK,gBAAgB,YAAY;AAC1C,wBAAc,KAAK,YAAY,GAAG;AAAA,QACpC,WAAW,OAAO,KAAK,gBAAgB,UAAU;AAC/C,gBAAM,SAAS,IAAI,IAAI,KAAK,WAAW;AACvC,iBAAO,aAAa,IAAI,aAAa,GAAG;AACxC,wBAAc,OAAO,SAAS;AAAA,QAChC;AAAA,MACF;AAEA,aAAO;AAAA,QACL,IAAI;AAAA,QACJ;AAAA,QACA,KAAK;AAAA,QACL;AAAA,MACF;AAAA,IACF;AAAA;AAAA,EAEa,MACX,KAGA;AAAA;AACA,UAAI;AACF,cAAM,SAAS,KAAK,mBAAmB,GAAG;AAE1C,aAAK,OAAO,MAAM,gBAAgB,EAAE,KAAK,OAAO,CAAC;AAEjD,cAAM,KAAK,yBAAyB,MAAM;AAC1C,cAAM,KAAK,iBAAiB,QAAQ,gBAAe,YAAY,SAAS;AAExE,eAAO;AAAA,UACL,IAAI;AAAA,UACJ,KAAK;AAAA,QACP;AAAA,MACF,SAAS,GAAP;AACA,aAAK,OAAO,MAAM,uBAAuB,EAAE,KAAK,OAAO,EAAE,CAAC;AAC1D,eAAO;AAAA,UACL,IAAI;AAAA,UACJ;AAAA,UACA,OAAO;AAAA,QACT;AAAA,MACF;AAAA,IACF;AAAA;AAAA,EAEa,MACX,KAGA;AAAA;AACA,UAAI;AACF,cAAM,SAAS,KAAK,mBAAmB,GAAG;AAE1C,aAAK,OAAO,MAAM,gBAAgB,EAAE,KAAK,OAAO,CAAC;AAEjD,cAAM,KAAK,yBAAyB,MAAM;AAC1C,cAAM,KAAK,iBAAiB,QAAQ,gBAAe,YAAY,SAAS;AAExE,eAAO;AAAA,UACL,IAAI;AAAA,UACJ,KAAK;AAAA,QACP;AAAA,MACF,SAAS,GAAP;AACA,aAAK,OAAO,MAAM,uBAAuB,EAAE,KAAK,OAAO,EAAE,CAAC;AAC1D,eAAO;AAAA,UACL,IAAI;AAAA,UACJ;AAAA,UACA,OAAO;AAAA,QACT;AAAA,MACF;AAAA,IACF;AAAA;AAAA,EAEa,OACX,KAGA;AAAA;AACA,UAAI;AACF,cAAM,SAAS,KAAK,mBAAmB,GAAG;AAE1C,aAAK,OAAO,MAAM,gBAAgB,EAAE,KAAK,OAAO,CAAC;AAEjD,cAAM,KAAK;AAAA,UACT;AAAA,UACA,gBAAe,YAAY;AAAA,QAC7B;AAEA,eAAO;AAAA,UACL,IAAI;AAAA,UACJ,KAAK;AAAA,QACP;AAAA,MACF,SAAS,GAAP;AACA,aAAK,OAAO,MAAM,wBAAwB,EAAE,KAAK,OAAO,EAAE,CAAC;AAC3D,eAAO;AAAA,UACL,IAAI;AAAA,UACJ;AAAA,UACA,OAAO;AAAA,QACT;AAAA,MACF;AAAA,IACF;AAAA;AAAA,EAEQ,mBAAmB,KAAqB;AAC9C,SAAK,OAAO,MAAM,kBAAkB,EAAE,IAAI,CAAC;AAC3C,QAAI;AACF,YAAM,gBAAgB,aAAa,KAAK;AAAA,QACtC,UAAU;AAAA,QACV,qBAAqB;AAAA,MACvB,CAAC;AAED,WAAK,OAAO,MAAM,kBAAkB,EAAE,MAAM,KAAK,IAAI,cAAc,CAAC;AAEpE,YAAM,YAAY,IAAI,IAAI,aAAa;AAEvC,WAAK,OAAO,MAAM,2BAA2B,EAAE,KAAK,UAAU,SAAS,CAAC;AAExE,YAAM,wBAAwB,YAAY,UAAU,QAAQ;AAE5D,WAAK,OAAO,MAAM,iBAAiB,EAAE,sBAAsB,CAAC;AAE5D,UAAI,sBAAsB,aAAa,aAAa;AAClD,cAAM,IAAI,iBAAiB,2CAA2C;AAAA,MACxE;AAEA,UAAI,sBAAsB,MAAM;AAC9B,cAAM,IAAI;AAAA,UACR;AAAA,QACF;AAAA,MACF;AAEA,UAAI,CAAC,sBAAsB,QAAQ;AACjC,cAAM,IAAI,iBAAiB,wBAAwB;AAAA,MACrD;AAEA,YAAM,SAAS,sBAAsB;AAErC,aAAO;AAAA,IACT,SAAS,GAAP;AACA,UAAI,aAAa,kBAAkB;AACjC,cAAM;AAAA,MACR,OAAO;AACL,aAAK,OAAO,MAAM,0BAA0B,EAAE,KAAK,OAAO,EAAE,CAAC;AAC7D,cAAM,IAAI,iBAAiB,wBAAwB;AAAA,MACrD;AAAA,IACF;AAAA,EACF;AAAA,EAEc,yBAAyB,QAA+B;AAAA;AACpE,YAAM,KAAK;AAAA,QACT;AAAA,QACA,gBAAe,YAAY;AAAA,MAC7B;AACA,YAAM,KAAK;AAAA,QACT;AAAA,QACA,gBAAe,YAAY;AAAA,MAC7B;AAAA,IACF;AAAA;AAAA,EAEc,wBACZ,QACA,KACe;AAAA;AACf,YAAM,OAAO,MAAM,KAAK,QAAQ,IAAI,GAAG;AAEvC,UAAI,CAAC,MAAM;AACT;AAAA,MACF;AAEA,YAAM,OAAO,MAAM,KAAK,mBAAmB,GAAG;AAE9C,UAAI,CAAC,KAAK,KAAK,QAAQ,SAAS,MAAM,GAAG;AACvC;AAAA,MACF;AAEA,WAAK,KAAK,UAAU,KAAK,KAAK,QAAQ,OAAO,CAAC,MAAM,MAAM,MAAM;AAEhE,YAAM,KAAK,iBAAiB,KAAK,IAAI;AAAA,IACvC;AAAA;AAAA,EAEc,iBAAiB,QAAgB,KAA4B;AAAA;AACzE,YAAM,OAAO,MAAM,KAAK,mBAAmB,GAAG;AAE9C,UAAI,KAAK,KAAK,QAAQ,SAAS,MAAM,GAAG;AACtC;AAAA,MACF;AAEA,WAAK,KAAK,QAAQ,KAAK,MAAM;AAE7B,YAAM,KAAK,iBAAiB,KAAK,IAAI;AAAA,IACvC;AAAA;AAAA,EAEc,eAAe,QAAgB,KAA+B;AAAA;AAC1E,YAAM,OAAO,MAAM,KAAK,mBAAmB,GAAG;AAC9C,aAAO,KAAK,KAAK,QAAQ,SAAS,MAAM;AAAA,IAC1C;AAAA;AAAA,EAEc,mBACZ,KACgD;AAAA;AAChD,YAAM,OAAO,MAAM,KAAK,QAAQ,IAAI,GAAG;AAEvC,UAAI,CAAC,MAAM;AACT,cAAMC,QAA8C;AAAA,UAClD,SAAS;AAAA,UACT,MAAM;AAAA,YACJ,SAAS,CAAC;AAAA,UACZ;AAAA,QACF;AACA,cAAM,KAAK,iBAAiB,KAAKA,KAAI;AACrC,eAAOA;AAAA,MACT;AAEA,YAAM,OAAO,gBAAe,OAAO,MAAM,KAAK,MAAM,IAAI,CAAC;AAEzD,aAAO;AAAA,IACT;AAAA;AAAA,EAEc,iBACZ,KACA,MACe;AAAA;AACf,YAAM,KAAK,QAAQ,IAAI,KAAK,KAAK,UAAU,IAAI,CAAC;AAAA,IAClD;AAAA;AAAA,EAEc,mBACZ,QAC8B;AAAA;AAC9B,UACE,MAAM,KAAK,eAAe,QAAQ,gBAAe,YAAY,UAAU,GACvE;AACA,eAAO;AAAA,MACT,WACE,MAAM,KAAK,eAAe,QAAQ,gBAAe,YAAY,SAAS,GACtE;AACA,eAAO;AAAA,MACT,WACE,MAAM,KAAK,eAAe,QAAQ,gBAAe,YAAY,SAAS,GACtE;AACA,eAAO;AAAA,MACT,OAAO;AACL,eAAO;AAAA,MACT;AAAA,IACF;AAAA;AACF;AA1aa,gBACJ,cAAc;AAAA,EACnB,WAAW;AAAA,EACX,WAAW;AAAA,EACX,YAAY;AACd;AALW,gBAOa,0BACtB;AARS,gBASa,SAAS,EAAE,OAAO;AAAA,EACxC,SAAS,EAAE,QAAQ,CAAC;AAAA,EACpB,MAAM,EAAE,OAAO;AAAA,IACb,SAAS,EAAE,MAAM,EAAE,OAAO,CAAC;AAAA,EAC7B,CAAC;AACH,CAAC;AAdI,IAAM,iBAAN","sourcesContent":["const ContinueAtOwnRisk = \"CHAINPATROL_CONTINUE_AT_OWN_RISK\";\nconst IgnorelistUpdated = \"CHAINPATROL_IGNORELIST_UPDATED\";\nconst CloseCurrentTab = \"CHAINPATROL_CLOSE_CURRENT_TAB\";\n\nexport const Events = {\n ContinueAtOwnRisk,\n IgnorelistUpdated,\n CloseCurrentTab,\n} as const;\n\nexport type EventData = {\n [ContinueAtOwnRisk]: {\n domain: string;\n };\n [IgnorelistUpdated]: {\n domain: string;\n };\n [CloseCurrentTab]: {};\n};\n","export enum LogLevel {\n DEBUG,\n INFO,\n WARN,\n ERROR,\n NONE,\n}\n\nexport class Logger {\n private meta: Record<string, unknown> = {};\n private minLevel: LogLevel;\n\n constructor(\n meta?: Record<string, unknown>,\n minLevel: LogLevel = LogLevel.NONE\n ) {\n if (meta) {\n this.meta = meta;\n }\n this.minLevel = minLevel;\n }\n\n public with(fields: Record<string, unknown>) {\n return new Logger({ ...this.meta, ...fields }, this.minLevel);\n }\n\n public debug(message: string, fields?: Record<string, unknown>) {\n this.log(LogLevel.DEBUG, message, fields);\n }\n\n public info(message: string, fields?: Record<string, unknown>) {\n this.log(LogLevel.INFO, message, fields);\n }\n\n public warn(message: string, fields?: Record<string, unknown>) {\n this.log(LogLevel.WARN, message, fields);\n }\n\n public error(message: string, fields?: Record<string, unknown>) {\n this.log(LogLevel.ERROR, message, fields);\n }\n\n private log(\n level: LogLevel,\n message: string,\n fields?: Record<string, unknown>\n ) {\n if (level < this.minLevel) {\n return; // Skip logging if log level is lower than minimum level\n }\n\n const logObj = { message, data: { ...fields }, ...this.meta };\n const logString = JSON.stringify(logObj, null, 2);\n console.log(`[${LogLevel[level].toUpperCase()}] ${logString}`);\n }\n}\n","import { EventData } from \"./events\";\nimport { Logger } from \"./logger\";\n\ntype Message<EventType extends keyof EventData> = {\n type: EventType;\n data: EventData[EventType];\n _meta: {\n id: string;\n origin: string;\n };\n};\n\nfunction getExtensionRuntime(): typeof chrome.runtime {\n if ((globalThis as any).browser?.runtime) {\n return (globalThis as any).browser.runtime;\n }\n if (globalThis.chrome?.runtime) {\n return globalThis.chrome.runtime;\n }\n throw new Error(\"No extension runtime found\");\n}\n\nfunction isExtensionHost() {\n return (\n !!(globalThis as any).browser?.runtime ||\n !!(globalThis as any).chrome?.runtime\n );\n}\n\nfunction isContentScript() {\n return isExtensionHost() && isBrowserHost();\n}\n\nfunction isBackgroundScript() {\n return isExtensionHost() && !isBrowserHost();\n}\n\nfunction isBrowserHost() {\n return !!(globalThis as any).window;\n}\n\ntype Handle = {\n addListener: (callback: (message: any) => void) => void;\n removeListener: (callback: (message: any) => void) => void;\n postMessage: (message: any) => void;\n};\n\nfunction getBackgroundScriptHandle(): Handle {\n const runtime = getExtensionRuntime();\n return {\n addListener: (callback: (message: any) => void) => {\n runtime.onMessage.addListener(callback);\n },\n removeListener: (callback: (message: any) => void) => {\n runtime.onMessage.removeListener(callback);\n },\n postMessage: async (message: any) => {\n const [tab] = await globalThis.chrome.tabs.query({\n active: true,\n lastFocusedWindow: true,\n });\n if (!tab.id || tab.id === globalThis.chrome.tabs.TAB_ID_NONE) {\n console.error(\"No active tab found\");\n return;\n }\n globalThis.chrome.tabs.sendMessage(tab.id, message);\n },\n };\n}\n\nfunction getContentScriptHandle(): Handle {\n const runtime = getExtensionRuntime();\n return {\n addListener: (callback: (message: any) => void) => {\n runtime.onMessage.addListener(callback);\n },\n removeListener: (callback: (message: any) => void) => {\n runtime.onMessage.removeListener(callback);\n },\n postMessage: async (message: any) => {\n runtime.sendMessage(message).catch((error) => {\n console.error(\"Failed to send message\", { message, error });\n });\n },\n };\n}\n\nfunction getBrowserHandle(): Handle {\n return {\n addListener: (callback: (message: any) => void) => {\n globalThis.window.addEventListener(\"message\", (event) => {\n if (event.source !== globalThis.window) {\n return;\n }\n callback(event.data);\n });\n },\n removeListener: (callback: (message: any) => void) => {\n globalThis.window.removeEventListener(\"message\", callback);\n },\n postMessage: (message: any) => {\n globalThis.window.postMessage(message, \"*\");\n },\n };\n}\n\n/**\n * Relay contains methods for implementing an event relay. It is used to\n * forward events between Javascript contexts:\n *\n * `<window>` <-> `<content script>` <-> `<background script>`\n *\n * Call `Relay.send` to send an event from one context to another. Call\n * `Relay.on` to listen for events in the current context. Call `Relay.run`\n * to start listening for events in the current context and forward them\n * to all other contexts.\n */\nexport class Relay {\n protected static handles: Handle[] = [];\n private static readonly logger = new Logger({ component: \"Relay\" });\n\n static {\n if (isBackgroundScript()) {\n Relay.logger.info(\"Detected background script\");\n Relay.handles.push(getBackgroundScriptHandle());\n } else if (isContentScript()) {\n Relay.logger.info(\"Detected content script\");\n Relay.handles.push(getContentScriptHandle());\n Relay.handles.push(getBrowserHandle());\n } else if (isBrowserHost()) {\n Relay.logger.info(\"Detected browser host\");\n Relay.handles.push(getBrowserHandle());\n }\n }\n\n public static send<EventType extends keyof EventData>(\n type: EventType,\n data: EventData[EventType]\n ) {\n const message = {\n type,\n data,\n _meta: {\n id: Math.random().toString(36).substring(2, 9),\n origin: globalThis.location.origin,\n },\n } satisfies Message<EventType>;\n\n Relay.logger.debug(\"Sending message\", message);\n\n for (const handle of Relay.handles) {\n handle.postMessage(message);\n }\n }\n\n public static run(events: (keyof EventData)[]) {\n const listeners = new Set<(message: any) => void>();\n\n for (const handle of Relay.handles) {\n const listener = Relay.handleMessage.bind(null, handle, events);\n listeners.add(listener);\n handle.addListener(listener);\n }\n\n Relay.logger.debug(\"Started relay\", { events });\n\n return () => {\n for (const handle of Relay.handles) {\n for (const listener of listeners) {\n handle.removeListener(listener);\n }\n }\n\n Relay.logger.debug(\"Stopped relay\", { events });\n };\n }\n\n private static handleMessage(\n sourceHandle: Handle,\n events: (keyof EventData)[],\n message: any\n ) {\n if (!events.includes(message.type)) {\n Relay.logger.debug(\"Ignoring message\", { message });\n return;\n }\n\n const destinationHandles = Relay.handles.filter(\n (handle) => handle !== sourceHandle\n );\n\n for (const destinationHandle of destinationHandles) {\n destinationHandle.postMessage(message);\n }\n }\n\n public static on<EventType extends keyof EventData>(\n targetEvent: EventType,\n callback: (data: EventData[EventType]) => void\n ) {\n const listeners = new Set<(message: any) => void>();\n for (const handle of Relay.handles) {\n const listener = (message: any) => {\n if (message.type !== targetEvent) {\n Relay.logger.debug(\"Ignoring message\", { message });\n return;\n }\n callback(message.data);\n };\n listeners.add(listener);\n handle.addListener(listener);\n }\n\n return () => {\n for (const handle of Relay.handles) {\n for (const listener of listeners) {\n handle.removeListener(listener);\n }\n }\n };\n }\n}\n","import { parse as parseDomain } from \"tldts\";\nimport normalizeUrl from \"normalize-url\";\nimport { z } from \"zod\";\n\nimport { AssetStatus, ChainPatrolClient } from \"./client\";\nimport { Memory } from \"./storage\";\nimport type { Storage } from \"./storage/types\";\nimport { Logger } from \"./logger\";\n\ntype Prettify<T> = T extends infer U ? (U extends string ? U : never) : never;\n\nexport type DetectorAssetStatus = Prettify<AssetStatus | \"IGNORED\">;\n\ntype Mode = \"cloud\" | \"local\";\n\n// Branded type for domain strings\ntype Domain = string & { __domain: never };\n\nexport type URLResult =\n | {\n ok: true;\n status: DetectorAssetStatus;\n url: string;\n redirectUrl?: string;\n }\n | {\n ok: false;\n url: string;\n error: string;\n };\n\nexport class DomainParseError extends Error {\n constructor(message: string) {\n super(message);\n this.name = \"DomainParseError\";\n }\n}\n\nexport class ThreatDetector {\n static StorageKeys = {\n ALLOWLIST: \"chainpatrol.allowed\",\n BLOCKLIST: \"chainpatrol.blocked\",\n IGNORELIST: \"chainpatrol.ignored\",\n };\n\n private static readonly CHAINPATROL_WARNING_URL =\n \"https://app.chainpatrol.io/warning\";\n private static readonly Schema = z.object({\n version: z.literal(1),\n data: z.object({\n domains: z.array(z.string()),\n }),\n });\n\n private mode: Mode;\n private client?: ChainPatrolClient;\n private storage: Storage;\n private redirectUrl?: string | ((url: string) => string);\n private readonly logger = new Logger({ component: \"ThreatDetector\" });\n\n constructor({\n mode,\n storage,\n redirectUrl,\n }: {\n mode: \"local\";\n storage?: Storage;\n redirectUrl?: string | ((url: string) => string);\n });\n\n constructor({\n mode,\n apiKey,\n storage,\n redirectUrl,\n }: {\n mode: \"cloud\";\n apiKey: string;\n storage?: Storage;\n redirectUrl?: string | ((url: string) => string);\n });\n\n constructor({\n mode,\n apiKey,\n proxyUrl,\n storage,\n redirectUrl,\n }: {\n mode: \"cloud\";\n apiKey: string;\n proxyUrl?: string;\n storage?: Storage;\n redirectUrl?: string | ((url: string) => string);\n });\n\n constructor({\n mode = \"cloud\",\n apiKey = \"\",\n storage = Memory(),\n proxyUrl,\n redirectUrl,\n }: {\n mode?: Mode;\n apiKey?: string;\n proxyUrl?: string;\n storage?: Storage;\n redirectUrl?: string | ((url: string) => string);\n }) {\n this.mode = mode;\n this.storage = storage;\n this.redirectUrl = redirectUrl ?? ThreatDetector.CHAINPATROL_WARNING_URL;\n if (mode === \"cloud\") {\n this.client = new ChainPatrolClient({\n apiKey: apiKey,\n baseUrl: proxyUrl,\n });\n }\n }\n\n public async url(url: string): Promise<URLResult> {\n this.logger.debug(\"Checking URL\", { url });\n\n let domains: Domain[];\n try {\n domains = this.generateDomains(url);\n } catch (e) {\n this.logger.error(\"Unable to parse domain\", { url, error: e });\n return {\n ok: false,\n url,\n error:\n e instanceof DomainParseError ? e.message : \"Unable to parse domain\",\n };\n }\n\n this.logger.debug(\"Generated domains\", { domains });\n\n let results = (\n await Promise.all(domains.map((domain) => this.urlHelper(domain, url)))\n ).filter(\n <T extends URLResult>(r: T): r is T extends { ok: true } ? T : never =>\n r.ok\n );\n\n if (results.length === 0) {\n return {\n ok: false,\n url,\n error: \"URL does not have a valid domain\",\n };\n }\n\n this.logger.debug(\"Results for domains\", { results });\n\n if (results.some((r) => r.status === \"IGNORED\")) {\n return {\n ok: true,\n status: \"IGNORED\",\n url,\n };\n }\n\n for (const result of results) {\n if (result.ok && result.status !== \"UNKNOWN\") {\n return result;\n }\n }\n\n return results[0];\n }\n\n private generateDomains(_url: string): Domain[] {\n const domain = this.parseDomainOrThrow(_url);\n\n const domains = [domain];\n\n const parsedDomain = parseDomain(domain);\n if (!parsedDomain.subdomain) {\n return domains;\n }\n\n const subdomainParts = parsedDomain.subdomain?.split(\".\") ?? [];\n\n for (let i = 0; i < subdomainParts.length; i++) {\n const subdomain = subdomainParts.slice(i).join(\".\");\n domains.unshift(`${subdomain}.${domain}` as Domain);\n }\n\n return domains;\n }\n\n private async urlHelper(domain: Domain, url: string): Promise<URLResult> {\n let status = await this.getStatusFromCache(domain);\n\n if (this.mode === \"cloud\" && this.client && status === \"UNKNOWN\") {\n try {\n const res = await this.client.asset.check({\n type: \"URL\",\n content: domain,\n });\n\n // Update cache storage\n this.logger.debug(\"Updating cache\", { domain, status: res.status });\n if (res.status === \"ALLOWED\") {\n this.addDomainToCache(domain, ThreatDetector.StorageKeys.ALLOWLIST);\n } else if (res.status === \"BLOCKED\") {\n this.addDomainToCache(domain, ThreatDetector.StorageKeys.BLOCKLIST);\n }\n\n status = res.status;\n } catch (e) {\n return {\n ok: false,\n url: domain,\n error: \"Unable to check URL\",\n };\n }\n }\n\n let redirectUrl: string | undefined;\n\n if (status === \"BLOCKED\") {\n if (typeof this.redirectUrl === \"function\") {\n redirectUrl = this.redirectUrl(url);\n } else if (typeof this.redirectUrl === \"string\") {\n const newUrl = new URL(this.redirectUrl);\n newUrl.searchParams.set(\"originUrl\", url);\n redirectUrl = newUrl.toString();\n }\n }\n\n return {\n ok: true,\n status,\n url: domain,\n redirectUrl,\n };\n }\n\n public async allow(\n url: string\n ): Promise<\n { ok: true; url: string } | { ok: false; url: string; error: string }\n > {\n try {\n const domain = this.parseDomainOrThrow(url);\n\n this.logger.debug(\"Allowing URL\", { url, domain });\n\n await this.invalidateDomainInCaches(domain);\n await this.addDomainToCache(domain, ThreatDetector.StorageKeys.ALLOWLIST);\n\n return {\n ok: true,\n url: domain,\n };\n } catch (e) {\n this.logger.error(\"Unable to allow URL\", { url, error: e });\n return {\n ok: false,\n url,\n error: \"Unable to allow URL\",\n };\n }\n }\n\n public async block(\n url: string\n ): Promise<\n { ok: true; url: string } | { ok: false; url: string; error: string }\n > {\n try {\n const domain = this.parseDomainOrThrow(url);\n\n this.logger.debug(\"Blocking URL\", { url, domain });\n\n await this.invalidateDomainInCaches(domain);\n await this.addDomainToCache(domain, ThreatDetector.StorageKeys.BLOCKLIST);\n\n return {\n ok: true,\n url: domain,\n };\n } catch (e) {\n this.logger.error(\"Unable to block URL\", { url, error: e });\n return {\n ok: false,\n url,\n error: \"Unable to block URL\",\n };\n }\n }\n\n public async ignore(\n url: string\n ): Promise<\n { ok: true; url: string } | { ok: false; url: string; error: string }\n > {\n try {\n const domain = this.parseDomainOrThrow(url);\n\n this.logger.debug(\"Ignoring URL\", { url, domain });\n\n await this.addDomainToCache(\n domain,\n ThreatDetector.StorageKeys.IGNORELIST\n );\n\n return {\n ok: true,\n url: domain,\n };\n } catch (e) {\n this.logger.error(\"Unable to ignore URL\", { url, error: e });\n return {\n ok: false,\n url,\n error: \"Unable to ignore URL\",\n };\n }\n }\n\n private parseDomainOrThrow(url: string): Domain {\n this.logger.debug(\"Parsing domain\", { url });\n try {\n const normalizedUrl = normalizeUrl(url, {\n stripWWW: false,\n removeTrailingSlash: false,\n });\n\n this.logger.debug(\"Normalized URL\", { from: url, to: normalizedUrl });\n\n const parsedURL = new URL(normalizedUrl);\n\n this.logger.debug(\"Extract domain from URL\", { url: parsedURL.hostname });\n\n const parsedSubdomainResult = parseDomain(parsedURL.hostname);\n\n this.logger.debug(\"Parsed domain\", { parsedSubdomainResult });\n\n if (parsedSubdomainResult.hostname === \"localhost\") {\n throw new DomainParseError(\"ThreatDetector does not support localhost\");\n }\n\n if (parsedSubdomainResult.isIp) {\n throw new DomainParseError(\n \"ThreatDetector does not support IP addresses\"\n );\n }\n\n if (!parsedSubdomainResult.domain) {\n throw new DomainParseError(\"Unable to parse domain\");\n }\n\n const domain = parsedSubdomainResult.domain as Domain;\n\n return domain;\n } catch (e) {\n if (e instanceof DomainParseError) {\n throw e;\n } else {\n this.logger.error(\"Unable to parse domain\", { url, error: e });\n throw new DomainParseError(\"Unable to parse domain\");\n }\n }\n }\n\n private async invalidateDomainInCaches(domain: Domain): Promise<void> {\n await this.invalidateDomainInCache(\n domain,\n ThreatDetector.StorageKeys.ALLOWLIST\n );\n await this.invalidateDomainInCache(\n domain,\n ThreatDetector.StorageKeys.BLOCKLIST\n );\n }\n\n private async invalidateDomainInCache(\n domain: Domain,\n key: string\n ): Promise<void> {\n const data = await this.storage.get(key);\n\n if (!data) {\n return;\n }\n\n const list = await this.getListFromStorage(key);\n\n if (!list.data.domains.includes(domain)) {\n return;\n }\n\n list.data.domains = list.data.domains.filter((u) => u !== domain);\n\n await this.setListInStorage(key, list);\n }\n\n private async addDomainToCache(domain: Domain, key: string): Promise<void> {\n const list = await this.getListFromStorage(key);\n\n if (list.data.domains.includes(domain)) {\n return;\n }\n\n list.data.domains.push(domain);\n\n await this.setListInStorage(key, list);\n }\n\n private async isDomainInList(domain: Domain, key: string): Promise<boolean> {\n const list = await this.getListFromStorage(key);\n return list.data.domains.includes(domain);\n }\n\n private async getListFromStorage(\n key: string\n ): Promise<z.infer<typeof ThreatDetector.Schema>> {\n const data = await this.storage.get(key);\n\n if (!data) {\n const list: z.infer<typeof ThreatDetector.Schema> = {\n version: 1,\n data: {\n domains: [],\n },\n };\n await this.setListInStorage(key, list);\n return list;\n }\n\n const list = ThreatDetector.Schema.parse(JSON.parse(data));\n\n return list;\n }\n\n private async setListInStorage(\n key: string,\n list: z.infer<typeof ThreatDetector.Schema>\n ): Promise<void> {\n await this.storage.set(key, JSON.stringify(list));\n }\n\n private async getStatusFromCache(\n domain: Domain\n ): Promise<DetectorAssetStatus> {\n if (\n await this.isDomainInList(domain, ThreatDetector.StorageKeys.IGNORELIST)\n ) {\n return \"IGNORED\";\n } else if (\n await this.isDomainInList(domain, ThreatDetector.StorageKeys.BLOCKLIST)\n ) {\n return \"BLOCKED\";\n } else if (\n await this.isDomainInList(domain, ThreatDetector.StorageKeys.ALLOWLIST)\n ) {\n return \"ALLOWED\";\n } else {\n return \"UNKNOWN\";\n }\n }\n}\n","// https://developer.mozilla.org/en-US/docs/Web/HTTP/Basics_of_HTTP/Data_URIs\nconst DATA_URL_DEFAULT_MIME_TYPE = 'text/plain';\nconst DATA_URL_DEFAULT_CHARSET = 'us-ascii';\n\nconst testParameter = (name, filters) => filters.some(filter => filter instanceof RegExp ? filter.test(name) : filter === name);\n\nconst supportedProtocols = new Set([\n\t'https:',\n\t'http:',\n\t'file:',\n]);\n\nconst hasCustomProtocol = urlString => {\n\ttry {\n\t\tconst {protocol} = new URL(urlString);\n\t\treturn protocol.endsWith(':') && !supportedProtocols.has(protocol);\n\t} catch {\n\t\treturn false;\n\t}\n};\n\nconst normalizeDataURL = (urlString, {stripHash}) => {\n\tconst match = /^data:(?<type>[^,]*?),(?<data>[^#]*?)(?:#(?<hash>.*))?$/.exec(urlString);\n\n\tif (!match) {\n\t\tthrow new Error(`Invalid URL: ${urlString}`);\n\t}\n\n\tlet {type, data, hash} = match.groups;\n\tconst mediaType = type.split(';');\n\thash = stripHash ? '' : hash;\n\n\tlet isBase64 = false;\n\tif (mediaType[mediaType.length - 1] === 'base64') {\n\t\tmediaType.pop();\n\t\tisBase64 = true;\n\t}\n\n\t// Lowercase MIME type\n\tconst mimeType = mediaType.shift()?.toLowerCase() ?? '';\n\tconst attributes = mediaType\n\t\t.map(attribute => {\n\t\t\tlet [key, value = ''] = attribute.split('=').map(string => string.trim());\n\n\t\t\t// Lowercase `charset`\n\t\t\tif (key === 'charset') {\n\t\t\t\tvalue = value.toLowerCase();\n\n\t\t\t\tif (value === DATA_URL_DEFAULT_CHARSET) {\n\t\t\t\t\treturn '';\n\t\t\t\t}\n\t\t\t}\n\n\t\t\treturn `${key}${value ? `=${value}` : ''}`;\n\t\t})\n\t\t.filter(Boolean);\n\n\tconst normalizedMediaType = [\n\t\t...attributes,\n\t];\n\n\tif (isBase64) {\n\t\tnormalizedMediaType.push('base64');\n\t}\n\n\tif (normalizedMediaType.length > 0 || (mimeType && mimeType !== DATA_URL_DEFAULT_MIME_TYPE)) {\n\t\tnormalizedMediaType.unshift(mimeType);\n\t}\n\n\treturn `data:${normalizedMediaType.join(';')},${isBase64 ? data.trim() : data}${hash ? `#${hash}` : ''}`;\n};\n\nexport default function normalizeUrl(urlString, options) {\n\toptions = {\n\t\tdefaultProtocol: 'http',\n\t\tnormalizeProtocol: true,\n\t\tforceHttp: false,\n\t\tforceHttps: false,\n\t\tstripAuthentication: true,\n\t\tstripHash: false,\n\t\tstripTextFragment: true,\n\t\tstripWWW: true,\n\t\tremoveQueryParameters: [/^utm_\\w+/i],\n\t\tremoveTrailingSlash: true,\n\t\tremoveSingleSlash: true,\n\t\tremoveDirectoryIndex: false,\n\t\tremoveExplicitPort: false,\n\t\tsortQueryParameters: true,\n\t\t...options,\n\t};\n\n\t// Legacy: Append `:` to the protocol if missing.\n\tif (typeof options.defaultProtocol === 'string' && !options.defaultProtocol.endsWith(':')) {\n\t\toptions.defaultProtocol = `${options.defaultProtocol}:`;\n\t}\n\n\turlString = urlString.trim();\n\n\t// Data URL\n\tif (/^data:/i.test(urlString)) {\n\t\treturn normalizeDataURL(urlString, options);\n\t}\n\n\tif (hasCustomProtocol(urlString)) {\n\t\treturn urlString;\n\t}\n\n\tconst hasRelativeProtocol = urlString.startsWith('//');\n\tconst isRelativeUrl = !hasRelativeProtocol && /^\\.*\\//.test(urlString);\n\n\t// Prepend protocol\n\tif (!isRelativeUrl) {\n\t\turlString = urlString.replace(/^(?!(?:\\w+:)?\\/\\/)|^\\/\\//, options.defaultProtocol);\n\t}\n\n\tconst urlObject = new URL(urlString);\n\n\tif (options.forceHttp && options.forceHttps) {\n\t\tthrow new Error('The `forceHttp` and `forceHttps` options cannot be used together');\n\t}\n\n\tif (options.forceHttp && urlObject.protocol === 'https:') {\n\t\turlObject.protocol = 'http:';\n\t}\n\n\tif (options.forceHttps && urlObject.protocol === 'http:') {\n\t\turlObject.protocol = 'https:';\n\t}\n\n\t// Remove auth\n\tif (options.stripAuthentication) {\n\t\turlObject.username = '';\n\t\turlObject.password = '';\n\t}\n\n\t// Remove hash\n\tif (options.stripHash) {\n\t\turlObject.hash = '';\n\t} else if (options.stripTextFragment) {\n\t\turlObject.hash = urlObject.hash.replace(/#?:~:text.*?$/i, '');\n\t}\n\n\t// Remove duplicate slashes if not preceded by a protocol\n\t// NOTE: This could be implemented using a single negative lookbehind\n\t// regex, but we avoid that to maintain compatibility with older js engines\n\t// which do not have support for that feature.\n\tif (urlObject.pathname) {\n\t\t// TODO: Replace everything below with `urlObject.pathname = urlObject.pathname.replace(/(?<!\\b[a-z][a-z\\d+\\-.]{1,50}:)\\/{2,}/g, '/');` when Safari supports negative lookbehind.\n\n\t\t// Split the string by occurrences of this protocol regex, and perform\n\t\t// duplicate-slash replacement on the strings between those occurrences\n\t\t// (if any).\n\t\tconst protocolRegex = /\\b[a-z][a-z\\d+\\-.]{1,50}:\\/\\//g;\n\n\t\tlet lastIndex = 0;\n\t\tlet result = '';\n\t\tfor (;;) {\n\t\t\tconst match = protocolRegex.exec(urlObject.pathname);\n\t\t\tif (!match) {\n\t\t\t\tbreak;\n\t\t\t}\n\n\t\t\tconst protocol = match[0];\n\t\t\tconst protocolAtIndex = match.index;\n\t\t\tconst intermediate = urlObject.pathname.slice(lastIndex, protocolAtIndex);\n\n\t\t\tresult += intermediate.replace(/\\/{2,}/g, '/');\n\t\t\tresult += protocol;\n\t\t\tlastIndex = protocolAtIndex + protocol.length;\n\t\t}\n\n\t\tconst remnant = urlObject.pathname.slice(lastIndex, urlObject.pathname.length);\n\t\tresult += remnant.replace(/\\/{2,}/g, '/');\n\n\t\turlObject.pathname = result;\n\t}\n\n\t// Decode URI octets\n\tif (urlObject.pathname) {\n\t\ttry {\n\t\t\turlObject.pathname = decodeURI(urlObject.pathname);\n\t\t} catch {}\n\t}\n\n\t// Remove directory index\n\tif (options.removeDirectoryIndex === true) {\n\t\toptions.removeDirectoryIndex = [/^index\\.[a-z]+$/];\n\t}\n\n\tif (Array.isArray(options.removeDirectoryIndex) && options.removeDirectoryIndex.length > 0) {\n\t\tlet pathComponents = urlObject.pathname.split('/');\n\t\tconst lastComponent = pathComponents[pathComponents.length - 1];\n\n\t\tif (testParameter(lastComponent, options.removeDirectoryIndex)) {\n\t\t\tpathComponents = pathComponents.slice(0, -1);\n\t\t\turlObject.pathname = pathComponents.slice(1).join('/') + '/';\n\t\t}\n\t}\n\n\tif (urlObject.hostname) {\n\t\t// Remove trailing dot\n\t\turlObject.hostname = urlObject.hostname.replace(/\\.$/, '');\n\n\t\t// Remove `www.`\n\t\tif (options.stripWWW && /^www\\.(?!www\\.)[a-z\\-\\d]{1,63}\\.[a-z.\\-\\d]{2,63}$/.test(urlObject.hostname)) {\n\t\t\t// Each label should be max 63 at length (min: 1).\n\t\t\t// Source: https://en.wikipedia.org/wiki/Hostname#Restrictions_on_valid_host_names\n\t\t\t// Each TLD should be up to 63 characters long (min: 2).\n\t\t\t// It is technically possible to have a single character TLD, but none currently exist.\n\t\t\turlObject.hostname = urlObject.hostname.replace(/^www\\./, '');\n\t\t}\n\t}\n\n\t// Remove query unwanted parameters\n\tif (Array.isArray(options.removeQueryParameters)) {\n\t\t// eslint-disable-next-line unicorn/no-useless-spread -- We are intentionally spreading to get a copy.\n\t\tfor (const key of [...urlObject.searchParams.keys()]) {\n\t\t\tif (testParameter(key, options.removeQueryParameters)) {\n\t\t\t\turlObject.searchParams.delete(key);\n\t\t\t}\n\t\t}\n\t}\n\n\tif (!Array.isArray(options.keepQueryParameters) && options.removeQueryParameters === true) {\n\t\turlObject.search = '';\n\t}\n\n\t// Keep wanted query parameters\n\tif (Array.isArray(options.keepQueryParameters) && options.keepQueryParameters.length > 0) {\n\t\t// eslint-disable-next-line unicorn/no-useless-spread -- We are intentionally spreading to get a copy.\n\t\tfor (const key of [...urlObject.searchParams.keys()]) {\n\t\t\tif (!testParameter(key, options.keepQueryParameters)) {\n\t\t\t\turlObject.searchParams.delete(key);\n\t\t\t}\n\t\t}\n\t}\n\n\t// Sort query parameters\n\tif (options.sortQueryParameters) {\n\t\turlObject.searchParams.sort();\n\n\t\t// Calling `.sort()` encodes the search parameters, so we need to decode them again.\n\t\ttry {\n\t\t\turlObject.search = decodeURIComponent(urlObject.search);\n\t\t} catch {}\n\t}\n\n\tif (options.removeTrailingSlash) {\n\t\turlObject.pathname = urlObject.pathname.replace(/\\/$/, '');\n\t}\n\n\t// Remove an explicit port number, excluding a default port number, if applicable\n\tif (options.removeExplicitPort && urlObject.port) {\n\t\turlObject.port = '';\n\t}\n\n\tconst oldUrlString = urlString;\n\n\t// Take advantage of many of the Node `url` normalizations\n\turlString = urlObject.toString();\n\n\tif (!options.removeSingleSlash && urlObject.pathname === '/' && !oldUrlString.endsWith('/') && urlObject.hash === '') {\n\t\turlString = urlString.replace(/\\/$/, '');\n\t}\n\n\t// Remove ending `/` unless removeSingleSlash is false\n\tif ((options.removeTrailingSlash || urlObject.pathname === '/') && urlObject.hash === '' && options.removeSingleSlash) {\n\t\turlString = urlString.replace(/\\/$/, '');\n\t}\n\n\t// Restore relative protocol, if applicable\n\tif (hasRelativeProtocol && !options.normalizeProtocol) {\n\t\turlString = urlString.replace(/^http:\\/\\//, '//');\n\t}\n\n\t// Remove http/https\n\tif (options.stripProtocol) {\n\t\turlString = urlString.replace(/^(?:https?:)?\\/\\//, '');\n\t}\n\n\treturn urlString;\n}\n","import { Logger } from \"./logger\";\n\nexport type ChainPatrolClientOptions = {\n apiKey: string;\n baseUrl?: string;\n};\n\ntype ApiRequest = {\n path: string[];\n method: \"GET\" | \"POST\" | \"PUT\" | \"DELETE\";\n body?: unknown;\n};\n\nexport type AssetType = \"URL\" | \"PAGE\" | \"ADDRESS\";\nexport type AssetStatus = \"ALLOWED\" | \"BLOCKED\" | \"UNKNOWN\";\n\nfunction trimTrailingSlashes(url: string): string {\n return url.replace(/\\/+$/, \"\");\n}\n\nexport class ChainPatrolClient {\n public readonly baseUrl: string;\n private readonly apiKey: string;\n private readonly logger = new Logger({ component: \"ChainPatrolClient\" });\n\n constructor(options: ChainPatrolClientOptions) {\n this.baseUrl = options.baseUrl ?? \"https://app.chainpatrol.io/api/\";\n if (!options.apiKey) {\n throw new Error(\"ChainPatrol API key is required\");\n }\n this.apiKey = options.apiKey;\n }\n\n private async fetch<TResult = unknown>(req: ApiRequest): Promise<TResult> {\n const url = `${trimTrailingSlashes(this.baseUrl)}/${req.path.join(\"/\")}`;\n this.logger.debug(\"fetch\", { url, req });\n const res = await fetch(url, {\n method: req.method,\n headers: {\n \"Content-Type\": \"application/json\",\n \"X-Api-Key\": this.apiKey,\n },\n body: JSON.stringify(req.body),\n });\n if (!res.ok) {\n throw new Error(await res.text());\n }\n return res.json();\n }\n\n public get asset() {\n return {\n check: async (req: {\n type: AssetType;\n content: string;\n }): Promise<{\n /**\n * \"ALLOWED\" - the asset is on the allowlist\n * \"BLOCKED\" - the asset is on the blocklist\n * \"UNKNOWN\" - the asset's status is not known\n */\n status: AssetStatus;\n /**\n * If the asset is allowed or blocked, this will be the reason why.\n * ChainPatrol aggregates data from multiple sources, so this will\n * tell you which source blocked or allowed the asset.\n *\n * ex. 'eth-phishing-detect' - the asset is on MetaMask's blocklist\n * 'reported' - the asset is on ChainPatrol's blocklist because\n * it was reported by a user\n */\n reason?: string;\n }> => {\n return await this.fetch<{\n status: AssetStatus;\n reason?: string;\n }>({\n path: [\"v2\", \"asset\", \"check\"],\n method: \"POST\",\n body: req,\n });\n },\n\n list: async (req: {\n /**\n * Asset type\n */\n type: AssetType;\n /**\n * Status of the assets to retrieve\n */\n status: AssetStatus;\n /**\n * The start date to list assets from. This should be in the format `YYYY-MM-DD` and is inclusive.\n */\n startDate?: string;\n /**\n * The end date to list assets from. This should be in the format `YYYY-MM-DD` and is inclusive.\n */\n endDate?: string;\n }): Promise<\n {\n content: string;\n type: AssetType;\n status: AssetStatus;\n }[]\n > => {\n return await this.fetch<\n {\n content: string;\n type: AssetType;\n status: AssetStatus;\n }[]\n >({\n path: [\"v2\", \"asset\", \"list\"],\n method: \"POST\",\n body: req,\n });\n },\n };\n }\n\n public get report() {\n return {\n create: async (req: {\n /** Report title */\n title: string;\n /** Report description */\n description: string;\n /** List of assets to report with the proposed status */\n assets: {\n content: string;\n status: AssetStatus;\n }[];\n /** Organization slug (provide this or `discordGuildId`) */\n organizationSlug?: string;\n /** Discord guild ID (provide this or `organizationSlug`) */\n discordGuildId?: string;\n /** Optional raw input of the assets */\n rawAssetsInput?: string;\n /** Optional List of URLs of images to attach to the report */\n attachmentUrls?: string[];\n /** Optional contact information of the reporter */\n contactInfo?: string;\n /** Optional ID of the reporter if they are a member on ChainPatrol */\n reporterId?: number;\n /**\n * Optional information about the reporter if they are reporting from\n * a platform other than ChainPatrol\n */\n externalReporter?: {\n platform: string;\n platformIdentifier: string;\n avatarUrl?: string;\n };\n }) => {\n return await this.fetch<{\n id: number;\n createdAt: string;\n organization: {\n id: number;\n slug: string;\n name: string;\n };\n }>({\n path: [\"v2\", \"report\", \"create\"],\n method: \"POST\",\n body: req,\n });\n },\n };\n }\n}\n","export * from \"./extension\";\nexport * from \"./browser\";\nexport * from \"./memory\";\nexport { defineStorage } from \"./define-storage\";\nexport * from \"./types\";\n","import { ThreatDetector } from \"../detector\";\nimport { Storage } from \"./types\";\n\nexport interface Context {\n keys: string[];\n}\n\nexport function defineStorage<T extends Storage>(\n config: (ctx: Context) => T\n): () => T {\n return () =>\n config({\n keys: Object.values(ThreatDetector.StorageKeys),\n });\n}\n","import { defineStorage } from \"./define-storage\";\n\nexport const Extension = defineStorage(({ keys }) => {\n return {\n get: async (key: string) => {\n const result = await chrome.storage.local.get(key);\n return result[key];\n },\n set: async (key: string, value: string) => {\n await chrome.storage.local.set({ [key]: value });\n },\n delete: async (key: string) => {\n await chrome.storage.local.remove(key);\n },\n size: async () => {\n const usageBytes = await chrome.storage.local.getBytesInUse(keys);\n return usageBytes;\n },\n };\n});\n","import { defineStorage } from \"./define-storage\";\n\nfunction isStorageAvailable(type: \"localStorage\" | \"sessionStorage\") {\n let storage;\n try {\n storage = window[type];\n const x = \"__storage_test__\";\n storage.setItem(x, x);\n storage.removeItem(x);\n return true;\n } catch (e) {\n return (\n e instanceof DOMException &&\n // everything except Firefox\n (e.code === 22 ||\n // Firefox\n e.code === 1014 ||\n // test name field too, because code might not be present\n // everything except Firefox\n e.name === \"QuotaExceededError\" ||\n // Firefox\n e.name === \"NS_ERROR_DOM_QUOTA_REACHED\") &&\n // acknowledge QuotaExceededError only if there's something already stored\n storage &&\n storage.length !== 0\n );\n }\n}\n\nexport const Browser = defineStorage(({ keys }) => {\n if (!isStorageAvailable(\"localStorage\")) {\n throw new Error(\"localStorage is not available\");\n }\n\n return {\n get: async (key: string) => {\n return localStorage.getItem(key);\n },\n set: async (key: string, value: string) => {\n localStorage.setItem(key, value);\n },\n delete: async (key: string) => {\n localStorage.removeItem(key);\n },\n size: async () => {\n let total = 0;\n for (let i = 0; i < localStorage.length; i++) {\n const key = localStorage.key(i);\n if (key && keys.includes(key)) {\n total += localStorage.getItem(key)?.length ?? 0;\n }\n }\n return total;\n },\n };\n});\n","import { defineStorage } from \"./define-storage\";\n\nexport const Memory = defineStorage(() => {\n const storage = new Map<string, string>();\n return {\n get: async (key: string) => {\n return storage.get(key) || null;\n },\n set: async (key: string, value: string) => {\n storage.set(key, value);\n },\n delete: async (key: string) => {\n storage.delete(key);\n },\n size: async () => {\n let total = 0;\n for (const value of storage.values()) {\n total += value.length;\n }\n return total;\n },\n };\n});\n"]}
|
package/package.json
CHANGED
|
@@ -1,8 +1,16 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@chainpatrol/sdk",
|
|
3
|
-
"description": "ChainPatrol SDK",
|
|
4
|
-
"author": "
|
|
5
|
-
"version": "0.1
|
|
3
|
+
"description": "The official ChainPatrol SDK",
|
|
4
|
+
"author": "Umar Ahmed <umar@chainpatrol.io>",
|
|
5
|
+
"version": "0.2.1",
|
|
6
|
+
"license": "MIT",
|
|
7
|
+
"homepage": "https://chainpatrol.io/docs/sdk",
|
|
8
|
+
"keywords": [
|
|
9
|
+
"chainpatrol",
|
|
10
|
+
"sdk",
|
|
11
|
+
"web3",
|
|
12
|
+
"api"
|
|
13
|
+
],
|
|
6
14
|
"main": "./dist/index.js",
|
|
7
15
|
"module": "./dist/index.mjs",
|
|
8
16
|
"types": "./dist/index.d.ts",
|