@keplr-wallet/router 0.9.0 → 0.9.12-rc.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (92) hide show
  1. package/build/index.d.ts +1 -3
  2. package/build/index.js +1 -3
  3. package/build/index.js.map +1 -1
  4. package/build/json-uint8-array/hex.d.ts +2 -0
  5. package/build/json-uint8-array/hex.js +31 -0
  6. package/build/json-uint8-array/hex.js.map +1 -0
  7. package/build/json-uint8-array/index.js +4 -3
  8. package/build/json-uint8-array/index.js.map +1 -1
  9. package/build/json-uint8-array/json.spec.js +5 -6
  10. package/build/json-uint8-array/json.spec.js.map +1 -1
  11. package/build/message.d.ts +5 -0
  12. package/build/message.js.map +1 -1
  13. package/build/router/index.d.ts +22 -3
  14. package/build/router/index.js +54 -12
  15. package/build/router/index.js.map +1 -1
  16. package/build/types.d.ts +2 -2
  17. package/package.json +2 -7
  18. package/src/index.ts +1 -3
  19. package/src/json-uint8-array/hex.ts +28 -0
  20. package/src/json-uint8-array/index.ts +7 -6
  21. package/src/json-uint8-array/json.spec.ts +0 -1
  22. package/src/message.ts +6 -0
  23. package/src/router/index.ts +64 -3
  24. package/src/types.ts +8 -2
  25. package/build/env/content-script.d.ts +0 -4
  26. package/build/env/content-script.js +0 -18
  27. package/build/env/content-script.js.map +0 -1
  28. package/build/env/extension.d.ts +0 -5
  29. package/build/env/extension.js +0 -127
  30. package/build/env/extension.js.map +0 -1
  31. package/build/env/extension.spec.d.ts +0 -1
  32. package/build/env/extension.spec.js +0 -33
  33. package/build/env/extension.spec.js.map +0 -1
  34. package/build/env/index.d.ts +0 -3
  35. package/build/env/index.js +0 -16
  36. package/build/env/index.js.map +0 -1
  37. package/build/env/mock.d.ts +0 -7
  38. package/build/env/mock.js +0 -23
  39. package/build/env/mock.js.map +0 -1
  40. package/build/guard/content-script.d.ts +0 -4
  41. package/build/guard/content-script.js +0 -14
  42. package/build/guard/content-script.js.map +0 -1
  43. package/build/guard/extension.d.ts +0 -5
  44. package/build/guard/extension.js +0 -27
  45. package/build/guard/extension.js.map +0 -1
  46. package/build/guard/index.d.ts +0 -3
  47. package/build/guard/index.js +0 -16
  48. package/build/guard/index.js.map +0 -1
  49. package/build/guard/mock.d.ts +0 -5
  50. package/build/guard/mock.js +0 -10
  51. package/build/guard/mock.js.map +0 -1
  52. package/build/mock/mock.spec.d.ts +0 -1
  53. package/build/mock/mock.spec.js +0 -118
  54. package/build/mock/mock.spec.js.map +0 -1
  55. package/build/requester/content-script.d.ts +0 -5
  56. package/build/requester/content-script.js +0 -51
  57. package/build/requester/content-script.js.map +0 -1
  58. package/build/requester/extension.d.ts +0 -6
  59. package/build/requester/extension.js +0 -59
  60. package/build/requester/extension.js.map +0 -1
  61. package/build/requester/index.d.ts +0 -3
  62. package/build/requester/index.js +0 -16
  63. package/build/requester/index.js.map +0 -1
  64. package/build/requester/mock.d.ts +0 -8
  65. package/build/requester/mock.js +0 -52
  66. package/build/requester/mock.js.map +0 -1
  67. package/build/router/extension.d.ts +0 -9
  68. package/build/router/extension.js +0 -77
  69. package/build/router/extension.js.map +0 -1
  70. package/build/router/mock.d.ts +0 -17
  71. package/build/router/mock.js +0 -59
  72. package/build/router/mock.js.map +0 -1
  73. package/build/router/types.d.ts +0 -22
  74. package/build/router/types.js +0 -57
  75. package/build/router/types.js.map +0 -1
  76. package/src/env/content-script.ts +0 -18
  77. package/src/env/extension.spec.ts +0 -77
  78. package/src/env/extension.ts +0 -151
  79. package/src/env/index.ts +0 -3
  80. package/src/env/mock.ts +0 -23
  81. package/src/guard/content-script.ts +0 -19
  82. package/src/guard/extension.ts +0 -36
  83. package/src/guard/index.ts +0 -3
  84. package/src/guard/mock.ts +0 -10
  85. package/src/mock/mock.spec.ts +0 -131
  86. package/src/requester/content-script.ts +0 -45
  87. package/src/requester/extension.ts +0 -66
  88. package/src/requester/index.ts +0 -3
  89. package/src/requester/mock.ts +0 -48
  90. package/src/router/extension.ts +0 -72
  91. package/src/router/mock.ts +0 -55
  92. package/src/router/types.ts +0 -64
@@ -1,36 +0,0 @@
1
- import { Env, Guard, MessageSender } from "../types";
2
- import { Message } from "../message";
3
-
4
- export class ExtensionGuards {
5
- static readonly checkOriginIsValid: Guard = (
6
- _: Omit<Env, "requestInteraction">,
7
- msg: Message<unknown>,
8
- sender: MessageSender
9
- ): Promise<void> => {
10
- // TODO: When is a url undefined?
11
- if (!sender.url) {
12
- throw new Error("url is empty");
13
- }
14
-
15
- if (!msg.origin) {
16
- throw new Error("origin is empty");
17
- }
18
-
19
- const url = new URL(sender.url);
20
- if (url.origin !== msg.origin) {
21
- throw new Error("Invalid origin");
22
- }
23
- return Promise.resolve();
24
- };
25
-
26
- static readonly checkMessageIsInternal: Guard = (
27
- env: Omit<Env, "requestInteraction">,
28
- msg: Message<unknown>,
29
- sender: MessageSender
30
- ): Promise<void> => {
31
- if (!env.isInternalMsg && !msg.approveExternal(env, sender)) {
32
- throw new Error("Permission rejected");
33
- }
34
- return Promise.resolve();
35
- };
36
- }
@@ -1,3 +0,0 @@
1
- export * from "./extension";
2
- export * from "./content-script";
3
- export * from "./mock";
package/src/guard/mock.ts DELETED
@@ -1,10 +0,0 @@
1
- import { Guard } from "../types";
2
- import { ExtensionGuards } from "./extension";
3
-
4
- export class MockGuards {
5
- static readonly checkOriginIsValid: Guard =
6
- ExtensionGuards.checkOriginIsValid;
7
-
8
- static readonly checkMessageIsInternal: Guard =
9
- ExtensionGuards.checkMessageIsInternal;
10
- }
@@ -1,131 +0,0 @@
1
- import assert from "assert";
2
- import { Message } from "../message";
3
- import { MockRouter, Router } from "../router";
4
- import { MockEnv } from "../env";
5
- import { MockMessageRequester } from "../requester";
6
- import { MockGuards } from "../guard";
7
-
8
- class MockMessage extends Message<boolean> {
9
- public static type() {
10
- return "mock";
11
- }
12
-
13
- route(): string {
14
- return "mock";
15
- }
16
-
17
- type(): string {
18
- return MockMessage.type();
19
- }
20
-
21
- validateBasic(): void {
22
- // noop
23
- }
24
- }
25
-
26
- class MockExternalMessage extends Message<boolean> {
27
- public static type() {
28
- return "mock-extern";
29
- }
30
-
31
- route(): string {
32
- return "mock-extern";
33
- }
34
-
35
- type(): string {
36
- return MockExternalMessage.type();
37
- }
38
-
39
- validateBasic(): void {
40
- // noop
41
- }
42
-
43
- approveExternal(): boolean {
44
- return true;
45
- }
46
- }
47
-
48
- describe("Test message permission", () => {
49
- const port = "port";
50
- const mockId = "mock";
51
- const mockUrl = "http://mock.com";
52
-
53
- const mockInternalRequester = new MockMessageRequester(mockId, mockUrl);
54
- const mockExternalRequester = new MockMessageRequester(
55
- mockId,
56
- "http://other.com"
57
- );
58
- const mockExternalRequester2 = new MockMessageRequester("other", mockUrl);
59
- const mockExternalRequester3 = new MockMessageRequester(
60
- "other",
61
- "http://other.com"
62
- );
63
-
64
- let router: Router | undefined;
65
- beforeEach(() => {
66
- // Init router for mocking.
67
- router = new MockRouter(new MockEnv(mockId, mockUrl).envProducer());
68
- router.addGuard(MockGuards.checkOriginIsValid);
69
- router.addGuard(MockGuards.checkMessageIsInternal);
70
-
71
- router.registerMessage(MockMessage);
72
- router.registerMessage(MockExternalMessage);
73
-
74
- router.addHandler("mock", () => true);
75
- router.addHandler("mock-extern", () => true);
76
-
77
- router.listen(port);
78
- });
79
-
80
- afterEach(() => {
81
- if (router) {
82
- router.unlisten();
83
- }
84
- });
85
-
86
- const testSendMessage = async (
87
- msg: Message<unknown>,
88
- isAllowExternal: boolean
89
- ) => {
90
- const result = await mockInternalRequester.sendMessage(port, msg);
91
- assert.strictEqual(result, true);
92
-
93
- if (isAllowExternal) {
94
- await assert.doesNotReject(async () => {
95
- const result = await mockExternalRequester.sendMessage(port, msg);
96
- assert.strictEqual(result, true);
97
- });
98
- await assert.doesNotReject(async () => {
99
- const result = await mockExternalRequester2.sendMessage(port, msg);
100
- assert.strictEqual(result, true);
101
- });
102
- await assert.doesNotReject(async () => {
103
- const result = await mockExternalRequester3.sendMessage(port, msg);
104
- assert.strictEqual(result, true);
105
- });
106
- } else {
107
- await assert.rejects(async () => {
108
- const result = await mockExternalRequester.sendMessage(port, msg);
109
- assert.strictEqual(result, true);
110
- });
111
- await assert.rejects(async () => {
112
- const result = await mockExternalRequester2.sendMessage(port, msg);
113
- assert.strictEqual(result, true);
114
- });
115
- await assert.rejects(async () => {
116
- const result = await mockExternalRequester3.sendMessage(port, msg);
117
- assert.strictEqual(result, true);
118
- });
119
- }
120
- };
121
-
122
- it("Basic message should be allowed only if it is from internal", async () => {
123
- const mockMsg = new MockMessage();
124
- await testSendMessage(mockMsg, false);
125
- });
126
-
127
- it("External message should be allowed event if it is from external", async () => {
128
- const mockMsg = new MockExternalMessage();
129
- await testSendMessage(mockMsg, true);
130
- });
131
- });
@@ -1,45 +0,0 @@
1
- import { MessageRequester } from "../types";
2
- import { Message } from "../message";
3
- import { JSONUint8Array } from "../json-uint8-array";
4
-
5
- // The message requester to send the message to the content scripts.
6
- // This will send message to the tab with the content script.
7
- // And, this can't handle the result of the message sending.
8
- // TODO: Research to improve this requester.
9
- export class ContentScriptMessageRequester implements MessageRequester {
10
- async sendMessage<M extends Message<unknown>>(
11
- port: string,
12
- msg: M
13
- ): Promise<M extends Message<infer R> ? R : never> {
14
- msg.validateBasic();
15
-
16
- // Set message's origin.
17
- // eslint-disable-next-line @typescript-eslint/ban-ts-comment
18
- // @ts-ignore
19
- msg["origin"] = window.location.origin;
20
-
21
- const wrappedMsg = JSONUint8Array.wrap(msg);
22
-
23
- const tabs = await browser.tabs.query({
24
- discarded: false,
25
- status: "complete",
26
- });
27
-
28
- for (let i = 0; i < tabs.length; i++) {
29
- const tabId = tabs[i].id;
30
- if (tabId) {
31
- try {
32
- await browser.tabs.sendMessage(tabId, {
33
- port,
34
- type: msg.type(),
35
- msg: wrappedMsg,
36
- });
37
- // Ignore the failure
38
- } catch {}
39
- }
40
- }
41
-
42
- // This requester can't handle the result of the message.
43
- return undefined as any;
44
- }
45
- }
@@ -1,66 +0,0 @@
1
- import { MessageRequester } from "../types";
2
- import { Message } from "../message";
3
- import { JSONUint8Array } from "../json-uint8-array";
4
-
5
- export class InExtensionMessageRequester implements MessageRequester {
6
- async sendMessage<M extends Message<unknown>>(
7
- port: string,
8
- msg: M
9
- ): Promise<M extends Message<infer R> ? R : never> {
10
- msg.validateBasic();
11
-
12
- // Set message's origin.
13
- // eslint-disable-next-line @typescript-eslint/ban-ts-comment
14
- // @ts-ignore
15
- msg["origin"] = window.location.origin;
16
-
17
- const result = JSONUint8Array.unwrap(
18
- await browser.runtime.sendMessage({
19
- port,
20
- type: msg.type(),
21
- msg: JSONUint8Array.wrap(msg),
22
- })
23
- );
24
-
25
- if (!result) {
26
- throw new Error("Null result");
27
- }
28
-
29
- if (result.error) {
30
- throw new Error(result.error);
31
- }
32
-
33
- return result.return;
34
- }
35
-
36
- static async sendMessageToTab<M extends Message<unknown>>(
37
- tabId: number,
38
- port: string,
39
- msg: M
40
- ): Promise<M extends Message<infer R> ? R : never> {
41
- msg.validateBasic();
42
-
43
- // Set message's origin.
44
- // eslint-disable-next-line @typescript-eslint/ban-ts-comment
45
- // @ts-ignore
46
- msg["origin"] = window.location.origin;
47
-
48
- const result = JSONUint8Array.unwrap(
49
- await browser.tabs.sendMessage(tabId, {
50
- port,
51
- type: msg.type(),
52
- msg: JSONUint8Array.wrap(msg),
53
- })
54
- );
55
-
56
- if (!result) {
57
- throw new Error("Null result");
58
- }
59
-
60
- if (result.error) {
61
- throw new Error(result.error);
62
- }
63
-
64
- return result.return;
65
- }
66
- }
@@ -1,3 +0,0 @@
1
- export * from "./extension";
2
- export * from "./content-script";
3
- export * from "./mock";
@@ -1,48 +0,0 @@
1
- import { MessageRequester } from "../types";
2
- import { Message } from "../message";
3
- import { JSONUint8Array } from "../json-uint8-array";
4
- import { MockRouter } from "../router";
5
- import { Result } from "../interfaces";
6
-
7
- export class MockMessageRequester implements MessageRequester {
8
- constructor(protected readonly id: string, protected readonly url: string) {}
9
-
10
- async sendMessage<M extends Message<unknown>>(
11
- port: string,
12
- msg: M
13
- ): Promise<M extends Message<infer R> ? R : never> {
14
- msg.validateBasic();
15
-
16
- // Set message's origin.
17
- // eslint-disable-next-line @typescript-eslint/ban-ts-comment
18
- // @ts-ignore
19
- msg["origin"] = new URL(this.url).origin;
20
-
21
- const result: Result = JSONUint8Array.unwrap(
22
- await new Promise((resolve) => {
23
- MockRouter.eventEmitter.emit("message", {
24
- message: {
25
- port,
26
- type: msg.type(),
27
- msg: JSONUint8Array.wrap(msg),
28
- },
29
- sender: {
30
- id: this.id,
31
- url: this.url,
32
- resolver: resolve,
33
- },
34
- });
35
- })
36
- );
37
-
38
- if (!result) {
39
- throw new Error("Null result");
40
- }
41
-
42
- if (result.error) {
43
- throw new Error(result.error);
44
- }
45
-
46
- return result.return;
47
- }
48
- }
@@ -1,72 +0,0 @@
1
- import { Router } from "./types";
2
- import { MessageSender } from "../types";
3
- import { Result } from "../interfaces";
4
-
5
- export class ExtensionRouter extends Router {
6
- listen(port: string): void {
7
- if (!port) {
8
- throw new Error("Empty port");
9
- }
10
-
11
- this.port = port;
12
- browser.runtime.onMessage.addListener(this.onMessage);
13
- // Although security considerations cross-extension communication are in place,
14
- // we have put in additional security measures by disbling extension-to-extension communication until a formal security audit has taken place.
15
- /*
16
- if (browser.runtime.onMessageExternal) {
17
- browser.runtime.onMessageExternal.addListener(this.onMessage);
18
- }
19
- */
20
- }
21
-
22
- unlisten(): void {
23
- this.port = "";
24
- browser.runtime.onMessage.removeListener(this.onMessage);
25
- // Although security considerations cross-extension communication are in place,
26
- // we have put in additional security measures by disbling extension-to-extension communication until a formal security audit has taken place.
27
- /*
28
- if (browser.runtime.onMessageExternal) {
29
- browser.runtime.onMessageExternal.removeListener(this.onMessage);
30
- }
31
- */
32
- }
33
-
34
- // You shouldn't set this handler as async funtion,
35
- // because mozila's extension polyfill deals with the message handler as resolved if it returns the `Promise`.
36
- // So, if this handler is async function, it always return the `Promise` if it returns `undefined` and it is dealt with as resolved.
37
- protected onMessage = (
38
- message: any,
39
- sender: MessageSender
40
- ): Promise<Result> | undefined => {
41
- if (message.port !== this.port) {
42
- return;
43
- }
44
-
45
- return this.onMessageHandler(message, sender);
46
- };
47
-
48
- protected async onMessageHandler(
49
- message: any,
50
- sender: MessageSender
51
- ): Promise<Result> {
52
- try {
53
- const result = await this.handleMessage(message, sender);
54
- return {
55
- return: result,
56
- };
57
- } catch (e) {
58
- console.log(
59
- `Failed to process msg ${message.type}: ${e?.message || e?.toString()}`
60
- );
61
- if (e) {
62
- return Promise.resolve({
63
- error: e.message || e.toString(),
64
- });
65
- } else {
66
- return Promise.resolve({
67
- error: "Unknown error, and error is null",
68
- });
69
- }
70
- }
71
- }
72
- }
@@ -1,55 +0,0 @@
1
- import { Router } from "./types";
2
- import { MessageSender } from "../types";
3
- import { Result } from "../interfaces";
4
- import { EventEmitter } from "events";
5
-
6
- export class MockRouter extends Router {
7
- public static eventEmitter = new EventEmitter();
8
-
9
- listen(port: string): void {
10
- if (!port) {
11
- throw new Error("Empty port");
12
- }
13
-
14
- this.port = port;
15
- MockRouter.eventEmitter.addListener("message", this.onMessage);
16
- }
17
-
18
- unlisten(): void {
19
- this.port = "";
20
- MockRouter.eventEmitter.removeListener("message", this.onMessage);
21
- }
22
-
23
- protected onMessage = async (params: {
24
- message: any;
25
- sender: MessageSender & {
26
- resolver: (result: Result) => void;
27
- };
28
- }): Promise<void> => {
29
- const { message, sender } = params;
30
- if (message.port !== this.port) {
31
- return;
32
- }
33
-
34
- try {
35
- const result = await this.handleMessage(message, sender);
36
- sender.resolver({
37
- return: result,
38
- });
39
- return;
40
- } catch (e) {
41
- console.log(
42
- `Failed to process msg ${message.type}: ${e?.message || e?.toString()}`
43
- );
44
- if (e) {
45
- sender.resolver({
46
- error: e.message || e.toString(),
47
- });
48
- } else {
49
- sender.resolver({
50
- error: "Unknown error, and error is null",
51
- });
52
- }
53
- }
54
- };
55
- }
@@ -1,64 +0,0 @@
1
- import { Message } from "../message";
2
- import { Handler } from "../handler";
3
- import { EnvProducer, Guard, MessageSender } from "../types";
4
- import { MessageRegistry } from "../encoding";
5
- import { JSONUint8Array } from "../json-uint8-array";
6
-
7
- export abstract class Router {
8
- protected msgRegistry: MessageRegistry = new MessageRegistry();
9
- protected registeredHandler: Map<string, Handler> = new Map();
10
-
11
- protected guards: Guard[] = [];
12
-
13
- protected port = "";
14
-
15
- constructor(protected readonly envProducer: EnvProducer) {}
16
-
17
- public registerMessage(
18
- msgCls: { new (...args: any): Message<unknown> } & { type(): string }
19
- ): void {
20
- this.msgRegistry.registerMessage(msgCls);
21
- }
22
-
23
- public addHandler(route: string, handler: Handler) {
24
- if (this.registeredHandler.has(route)) {
25
- throw new Error(`Already registered type ${route}`);
26
- }
27
-
28
- this.registeredHandler.set(route, handler);
29
- }
30
-
31
- public addGuard(guard: Guard): void {
32
- this.guards.push(guard);
33
- }
34
-
35
- public abstract listen(port: string): void;
36
-
37
- public abstract unlisten(): void;
38
-
39
- protected async handleMessage(
40
- message: any,
41
- sender: MessageSender
42
- ): Promise<unknown> {
43
- const msg = this.msgRegistry.parseMessage(JSONUint8Array.unwrap(message));
44
- const env = this.envProducer(sender);
45
-
46
- for (const guard of this.guards) {
47
- await guard(env, msg, sender);
48
- }
49
-
50
- // Can happen throw
51
- msg.validateBasic();
52
-
53
- const route = msg.route();
54
- if (!route) {
55
- throw new Error("Null router");
56
- }
57
- const handler = this.registeredHandler.get(route);
58
- if (!handler) {
59
- throw new Error("Can't get handler");
60
- }
61
-
62
- return JSONUint8Array.wrap(await handler(env, msg));
63
- }
64
- }