vigor-bridge 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,82 @@
1
+ type BridgeUtilCryptoResult = {
2
+ iv: Array<number>;
3
+ encrypted: Uint8Array<ArrayBuffer>;
4
+ };
5
+ type BridgeTokensType = {
6
+ validation: {
7
+ request: string;
8
+ receive: string;
9
+ };
10
+ };
11
+ type BridgeTokens = {
12
+ validation: string;
13
+ bridge: string;
14
+ testFn: string;
15
+ testResult: string;
16
+ portValidation: {
17
+ host: string;
18
+ remote: string;
19
+ };
20
+ directValidation: string;
21
+ };
22
+ type BridgeChannelListenerId = symbol & {
23
+ __brand__: 'Bridge Listener Id';
24
+ };
25
+ type BridgeChannelContent = any;
26
+ type BridgeValidationWrapper = (getEncrypted: (random: string) => BridgeUtilCryptoResult | Promise<BridgeUtilCryptoResult>) => Promise<(<T>(content: BridgeChannelContent) => any)>;
27
+ declare class BridgeDirect {
28
+ private listeners;
29
+ private host;
30
+ private readonly validation;
31
+ private caches;
32
+ constructor(listeners: Map<BridgeChannelListenerId, {
33
+ action: string;
34
+ callback: BridgeValidationWrapper;
35
+ type: string;
36
+ host: boolean;
37
+ }>, host: boolean, validation: string);
38
+ addEventListener(action: string, callback: (content: BridgeChannelContent) => void): {
39
+ id: BridgeChannelListenerId;
40
+ removeEventListener: () => boolean;
41
+ };
42
+ removeEventListener(listenerId: BridgeChannelListenerId): boolean;
43
+ postMessage(action: string, content: BridgeChannelContent): void;
44
+ handle(action: string, callback: <T>(content: BridgeChannelContent) => T | Promise<T>): void;
45
+ request(action: string, content: BridgeChannelContent): Promise<unknown>;
46
+ }
47
+ declare class BridgeChannel {
48
+ private readonly port;
49
+ private listeners;
50
+ private caches;
51
+ constructor(port: MessagePort);
52
+ addEventListener(action: string, callback: (content: BridgeChannelContent) => void): {
53
+ id: BridgeChannelListenerId;
54
+ removeEventListener: () => boolean;
55
+ };
56
+ removeEventListener(listenerId: BridgeChannelListenerId): boolean;
57
+ postMessage(action: string, content: BridgeChannelContent): void;
58
+ handle(action: string, callback: <T>(content: BridgeChannelContent) => T | Promise<T>): {
59
+ id: BridgeChannelListenerId;
60
+ removeEventListener: () => boolean;
61
+ };
62
+ request(action: string, content: BridgeChannelContent): Promise<unknown>;
63
+ static create(port: MessagePort, host: boolean, validation: {
64
+ host: string;
65
+ remote: string;
66
+ }): Promise<BridgeChannel>;
67
+ }
68
+ declare const BridgeEntry: {
69
+ create: () => {
70
+ certification: {
71
+ tokens: BridgeTokens;
72
+ type: BridgeTokensType;
73
+ };
74
+ bridge: Promise<BridgeDirect | BridgeChannel>;
75
+ };
76
+ connect: ({ tokens, type }: {
77
+ tokens: BridgeTokens;
78
+ type: BridgeTokensType;
79
+ }) => Promise<BridgeDirect | BridgeChannel>;
80
+ };
81
+ export default BridgeEntry;
82
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
package/dist/index.js ADDED
@@ -0,0 +1,571 @@
1
+ 'use strict';
2
+
3
+ Object.defineProperty(exports, '__esModule', { value: true });
4
+
5
+ const Bridge_Error_Messages = {
6
+ INVALID_TYPE: ({ expected, received }) => `Invalid Type: ${typeof received} (expected: ${expected.map(e => JSON.stringify(e)).join(', ')})`,
7
+ INVALID_VALIDATION: ({ expected, received }) => `Invalid Validation: ${typeof received} (expected: ${expected.join(', ')})`,
8
+ INVALID_PORT: ({ expected, received }) => `Invalid Type: ${typeof received} (expected: ${expected.map(e => JSON.stringify(e)).join(', ')})`,
9
+ MALICIOUS_DATA: ({ position, step }) => `Malicious Data Detected: ${position}`
10
+ };
11
+ class BridgeError extends Error {
12
+ code;
13
+ timestamp = new Date();
14
+ constructor(code, options) {
15
+ const messageFn = Bridge_Error_Messages[code];
16
+ const message = `[${code}] ${messageFn(options.data)}`;
17
+ super(message);
18
+ this.code = code;
19
+ this.name = new.target.name;
20
+ Object.assign(this, options);
21
+ Object.setPrototypeOf(this, new.target.prototype)(Error).captureStackTrace?.(this, new.target);
22
+ }
23
+ }
24
+ class BridgeConnectError extends BridgeError {
25
+ constructor(code, options) {
26
+ super(code, options);
27
+ }
28
+ }
29
+ class BridgeDirectError extends BridgeError {
30
+ constructor(code, options) {
31
+ super(code, options);
32
+ }
33
+ }
34
+ class BridgeChannelError extends BridgeError {
35
+ constructor(code, options) {
36
+ super(code, options);
37
+ }
38
+ }
39
+ class BridgeUtilCrypto {
40
+ static generateRandomHex(length = 100) {
41
+ const byteLength = Math.ceil(length / 2);
42
+ const array = new Uint8Array(byteLength);
43
+ self.crypto.getRandomValues(array);
44
+ const hex = Array.from(array)
45
+ .map(byte => byte.toString(16).padStart(2, '0'))
46
+ .join('');
47
+ return hex.substring(0, length);
48
+ }
49
+ static aes = {
50
+ convertPassword: async (passwordRaw) => {
51
+ const encoder = new TextEncoder();
52
+ const password = encoder.encode(passwordRaw.padEnd(32, '0').substring(0, 32));
53
+ return await window.crypto.subtle.importKey("raw", password, { name: "AES-GCM" }, false, ["encrypt", "decrypt"]);
54
+ },
55
+ encrypt: async (text, passwordRaw) => {
56
+ const encoder = new TextEncoder();
57
+ const password = await BridgeUtilCrypto.aes.convertPassword(passwordRaw);
58
+ const data = encoder.encode(text);
59
+ const iv = window.crypto.getRandomValues(new Uint8Array(12));
60
+ const encryptedBuffer = await window.crypto.subtle.encrypt({ name: "AES-GCM", iv: iv }, password, data);
61
+ return {
62
+ iv: Array.from(iv),
63
+ encrypted: new Uint8Array(encryptedBuffer)
64
+ };
65
+ },
66
+ decrypt: async ({ iv: ivArray, encrypted }, passwordRaw) => {
67
+ const decoder = new TextDecoder();
68
+ const password = await BridgeUtilCrypto.aes.convertPassword(passwordRaw);
69
+ const iv = new Uint8Array(ivArray);
70
+ const decryptedBuffer = await window.crypto.subtle.decrypt({
71
+ name: "AES-GCM",
72
+ iv
73
+ }, password, encrypted);
74
+ return decoder.decode(decryptedBuffer);
75
+ }
76
+ };
77
+ static hmac = {
78
+ convertPassword: async (passwordRaw) => {
79
+ const encoder = new TextEncoder();
80
+ const passwordBytes = encoder.encode(passwordRaw.padEnd(32, '0').substring(0, 32));
81
+ return await window.crypto.subtle.importKey("raw", passwordBytes, {
82
+ name: "HMAC",
83
+ hash: { name: "SHA-256" }
84
+ }, false, ["sign", "verify"]);
85
+ },
86
+ sign: async (text, passwordRaw) => {
87
+ const encoder = new TextEncoder();
88
+ const password = await BridgeUtilCrypto.hmac.convertPassword(passwordRaw);
89
+ const data = encoder.encode(text);
90
+ const encryptedBuffer = await window.crypto.subtle.sign("HMAC", password, data);
91
+ return new Uint8Array(encryptedBuffer);
92
+ },
93
+ verify: async (text, passwordRaw, signature) => {
94
+ const encoder = new TextEncoder();
95
+ const password = await BridgeUtilCrypto.hmac.convertPassword(passwordRaw);
96
+ const data = encoder.encode(text);
97
+ return await window.crypto.subtle.verify("HMAC", password, signature, data);
98
+ }
99
+ };
100
+ }
101
+ class BridgeUtilListener {
102
+ static listenerMap = new Map();
103
+ static addEventListener(callback) {
104
+ const listenerId = Symbol("Listener");
105
+ window.addEventListener("message", callback);
106
+ this.listenerMap.set(listenerId, callback);
107
+ return {
108
+ id: listenerId,
109
+ removeEventListener: () => this.removeEventListener(listenerId)
110
+ };
111
+ }
112
+ static removeEventListener(listenerId) {
113
+ const callback = this.listenerMap.get(listenerId);
114
+ if (!callback)
115
+ return false;
116
+ window.removeEventListener("message", callback);
117
+ this.listenerMap.delete(listenerId);
118
+ return true;
119
+ }
120
+ }
121
+ class BridgeDirect {
122
+ listeners;
123
+ host;
124
+ validation;
125
+ caches = [];
126
+ constructor(listeners, host, validation) {
127
+ this.listeners = listeners;
128
+ this.host = host;
129
+ this.validation = validation;
130
+ }
131
+ addEventListener(action, callback) {
132
+ const type = "normal";
133
+ for (const cache of this.caches) {
134
+ if (cache.action !== action || cache.type !== type)
135
+ continue;
136
+ callback(cache.content);
137
+ }
138
+ const listenerId = Symbol("LISTENER_NORMAL");
139
+ this.listeners.set(listenerId, {
140
+ action,
141
+ callback: async (getEncrypted) => {
142
+ const random = BridgeUtilCrypto.generateRandomHex();
143
+ const encryptedRandom = await getEncrypted(random);
144
+ const decryptedRandom = await BridgeUtilCrypto.aes.decrypt(encryptedRandom, this.validation);
145
+ if (decryptedRandom !== random)
146
+ throw new BridgeDirectError("MALICIOUS_DATA", {
147
+ data: { position: this.host ? "host" : "remote", step: 2 }
148
+ });
149
+ return callback;
150
+ },
151
+ type,
152
+ host: this.host
153
+ });
154
+ return {
155
+ id: listenerId,
156
+ removeEventListener: () => this.removeEventListener(listenerId)
157
+ };
158
+ }
159
+ removeEventListener(listenerId) {
160
+ return this.listeners.delete(listenerId);
161
+ }
162
+ postMessage(action, content) {
163
+ const type = "normal";
164
+ const targets = Array.from(this.listeners.values()).filter(listener => listener.action === action && listener.type === type && listener.host !== this.host);
165
+ const promises = targets.map(async (listener) => {
166
+ const callback = await listener.callback(async (random) => {
167
+ return await BridgeUtilCrypto.aes.encrypt(random, this.validation);
168
+ });
169
+ if (callback)
170
+ callback(content);
171
+ });
172
+ Promise.all(promises);
173
+ }
174
+ handle(action, callback) {
175
+ const type = "request";
176
+ for (const [listenerId, listener] of this.listeners) {
177
+ if (listener.action !== action || listener.type !== type)
178
+ continue;
179
+ this.listeners.delete(listenerId);
180
+ }
181
+ for (const cache of this.caches) {
182
+ if (cache.action !== action || cache.type !== type)
183
+ continue;
184
+ callback(cache.content);
185
+ }
186
+ const listenerId = Symbol("LISTENER_HANDLE");
187
+ this.listeners.set(listenerId, {
188
+ action,
189
+ callback: async (getEncrypted) => {
190
+ const random = BridgeUtilCrypto.generateRandomHex();
191
+ const encryptedRandom = await getEncrypted(random);
192
+ const decryptedRandom = await BridgeUtilCrypto.aes.decrypt(encryptedRandom, this.validation);
193
+ if (decryptedRandom !== random)
194
+ throw new BridgeDirectError("MALICIOUS_DATA", {
195
+ data: { position: this.host ? "host" : "remote", step: 2 }
196
+ });
197
+ return async (content) => {
198
+ const { requestId, data, host } = content;
199
+ try {
200
+ const result = await callback(data);
201
+ return {
202
+ action,
203
+ content: {
204
+ success: true,
205
+ data: result,
206
+ error: null,
207
+ responseId: requestId
208
+ },
209
+ type,
210
+ host
211
+ };
212
+ }
213
+ catch (error) {
214
+ return {
215
+ action,
216
+ content: {
217
+ success: false,
218
+ data: null,
219
+ error: (error instanceof Error) ? error.message : error,
220
+ responseId: requestId
221
+ },
222
+ type,
223
+ host
224
+ };
225
+ }
226
+ };
227
+ },
228
+ type,
229
+ host: this.host
230
+ });
231
+ }
232
+ request(action, content) {
233
+ return new Promise((resolve, reject) => {
234
+ const requestId = BridgeUtilCrypto.generateRandomHex();
235
+ const type = "request";
236
+ const listener = Array.from(this.listeners.values()).find(listener => listener.action === action && listener.type === type && listener.host !== this.host);
237
+ listener?.callback(async (random) => {
238
+ const encryptedRandom = await BridgeUtilCrypto.aes.encrypt(random, this.validation);
239
+ return encryptedRandom;
240
+ }).then(callback => callback({
241
+ action,
242
+ content: {
243
+ requestId,
244
+ data: content
245
+ },
246
+ type
247
+ }).then(({ content }) => {
248
+ const { success, data, error, responseId } = content;
249
+ if (responseId !== requestId)
250
+ return;
251
+ if (success)
252
+ resolve(data);
253
+ else
254
+ reject(error);
255
+ }));
256
+ });
257
+ }
258
+ }
259
+ class BridgeChannel {
260
+ port;
261
+ listeners = new Map();
262
+ caches = [];
263
+ constructor(port) {
264
+ this.port = port;
265
+ port.onmessage = ({ data }) => {
266
+ this.caches.push({ action: data.action, content: data.content, type: data.type });
267
+ for (const listener of this.listeners.values()) {
268
+ if (listener.action !== data.action || listener.type !== data.type)
269
+ continue;
270
+ listener.callback(data.content);
271
+ }
272
+ };
273
+ }
274
+ addEventListener(action, callback) {
275
+ const type = "normal";
276
+ for (const cache of this.caches) {
277
+ if (cache.action !== action || cache.type !== type)
278
+ continue;
279
+ callback(cache.content);
280
+ }
281
+ const listenerId = Symbol("LISTENER_NORMAL");
282
+ this.listeners.set(listenerId, { action, callback, type });
283
+ return {
284
+ id: listenerId,
285
+ removeEventListener: () => this.removeEventListener(listenerId)
286
+ };
287
+ }
288
+ removeEventListener(listenerId) {
289
+ return this.listeners.delete(listenerId);
290
+ }
291
+ postMessage(action, content) {
292
+ const type = "normal";
293
+ this.port.postMessage({
294
+ action,
295
+ content,
296
+ type
297
+ });
298
+ }
299
+ handle(action, callback) {
300
+ const type = "request";
301
+ for (const [listenerId, listener] of this.listeners) {
302
+ if (listener.action !== action || listener.type !== type)
303
+ continue;
304
+ this.listeners.delete(listenerId);
305
+ }
306
+ for (const cache of this.caches) {
307
+ if (cache.action !== action || cache.type !== type)
308
+ continue;
309
+ callback(cache.content);
310
+ }
311
+ const listenerId = Symbol("LISTENER_HANDLE");
312
+ this.listeners.set(listenerId, { action, callback: async (content) => {
313
+ const type = "response";
314
+ const { requestId, data } = content;
315
+ try {
316
+ const result = await callback(data);
317
+ this.port.postMessage({
318
+ action,
319
+ content: {
320
+ success: true,
321
+ data: result,
322
+ error: null,
323
+ responseId: requestId
324
+ },
325
+ type
326
+ });
327
+ }
328
+ catch (error) {
329
+ this.port.postMessage({
330
+ action,
331
+ content: {
332
+ success: false,
333
+ data: null,
334
+ error: (error instanceof Error) ? error.message : error,
335
+ responseId: requestId
336
+ },
337
+ type
338
+ });
339
+ }
340
+ }, type });
341
+ return {
342
+ id: listenerId,
343
+ removeEventListener: () => this.removeEventListener(listenerId)
344
+ };
345
+ }
346
+ request(action, content) {
347
+ return new Promise((resolve, reject) => {
348
+ const listenerId = Symbol("LISTENER_RESPONSE");
349
+ const requestId = BridgeUtilCrypto.generateRandomHex();
350
+ this.listeners.set(listenerId, { action, callback: (content) => {
351
+ const { success, data, error, responseId } = content;
352
+ if (responseId !== requestId)
353
+ return;
354
+ this.listeners.delete(listenerId);
355
+ if (success)
356
+ resolve(data);
357
+ else
358
+ reject(error);
359
+ }, type: "response" });
360
+ const type = "request";
361
+ this.port.postMessage({
362
+ action,
363
+ content: {
364
+ requestId,
365
+ data: content
366
+ },
367
+ type
368
+ });
369
+ });
370
+ }
371
+ static async create(port, host, validation) {
372
+ await new Promise((resolve, reject) => {
373
+ const random = BridgeUtilCrypto.generateRandomHex();
374
+ if (host) {
375
+ port.onmessage = async ({ data }) => {
376
+ if (data.type === 'port-validation-1') {
377
+ const encryptedRandom = await BridgeUtilCrypto.aes.encrypt(data.content.random, validation.remote);
378
+ port.postMessage({
379
+ type: 'port-validation-2',
380
+ content: {
381
+ random,
382
+ encrypted: encryptedRandom
383
+ }
384
+ });
385
+ }
386
+ else if (data.type === 'port-validation-3') {
387
+ const decryptedRandom = await BridgeUtilCrypto.aes.decrypt(data.content.encrypted, validation.host);
388
+ if (decryptedRandom !== random) {
389
+ port.close();
390
+ return reject(new BridgeChannelError("MALICIOUS_DATA", {
391
+ data: {
392
+ position: "host",
393
+ step: 3
394
+ }
395
+ }));
396
+ }
397
+ port.postMessage({
398
+ type: 'port-validation-4',
399
+ content: {}
400
+ });
401
+ resolve({});
402
+ }
403
+ else {
404
+ port.close();
405
+ return reject(new BridgeChannelError("MALICIOUS_DATA", {
406
+ data: {
407
+ position: "host",
408
+ step: 0
409
+ }
410
+ }));
411
+ }
412
+ };
413
+ }
414
+ else {
415
+ const portValidationRequest = setInterval(() => {
416
+ port.postMessage({
417
+ type: 'port-validation-1',
418
+ content: {
419
+ random
420
+ }
421
+ });
422
+ }, 100);
423
+ port.onmessage = async ({ data }) => {
424
+ clearInterval(portValidationRequest);
425
+ if (data.type === 'port-validation-2') {
426
+ const decryptedRandom = await BridgeUtilCrypto.aes.decrypt(data.content.encrypted, validation.remote);
427
+ if (decryptedRandom !== random) {
428
+ port.close();
429
+ return reject(new BridgeChannelError("MALICIOUS_DATA", {
430
+ data: {
431
+ position: "remote",
432
+ step: 2
433
+ }
434
+ }));
435
+ }
436
+ const encryptedRandom = await BridgeUtilCrypto.aes.encrypt(data.content.random, validation.host);
437
+ port.postMessage({
438
+ type: 'port-validation-3',
439
+ content: {
440
+ encrypted: encryptedRandom
441
+ }
442
+ });
443
+ }
444
+ else if (data.type === 'port-validation-4') {
445
+ resolve({});
446
+ }
447
+ else {
448
+ port.close();
449
+ return reject(new BridgeChannelError("MALICIOUS_DATA", {
450
+ data: {
451
+ position: "host",
452
+ step: 0
453
+ }
454
+ }));
455
+ }
456
+ };
457
+ }
458
+ });
459
+ return new BridgeChannel(port);
460
+ }
461
+ }
462
+ const BridgeEntry = {
463
+ create: () => {
464
+ const type = {
465
+ validation: {
466
+ request: BridgeUtilCrypto.generateRandomHex(),
467
+ receive: BridgeUtilCrypto.generateRandomHex()
468
+ }
469
+ };
470
+ const tokens = {
471
+ validation: BridgeUtilCrypto.generateRandomHex(),
472
+ bridge: BridgeUtilCrypto.generateRandomHex(),
473
+ testFn: BridgeUtilCrypto.generateRandomHex(),
474
+ testResult: BridgeUtilCrypto.generateRandomHex(),
475
+ portValidation: {
476
+ host: BridgeUtilCrypto.generateRandomHex(),
477
+ remote: BridgeUtilCrypto.generateRandomHex()
478
+ },
479
+ directValidation: BridgeUtilCrypto.generateRandomHex()
480
+ };
481
+ const bridge = new Promise(async (resolve, reject) => {
482
+ const connectReceive = BridgeUtilListener.addEventListener(async (event) => {
483
+ const { data } = event;
484
+ if (data.type !== type.validation.request)
485
+ return;
486
+ connectReceive.removeEventListener();
487
+ const main = window[tokens.bridge];
488
+ delete window[tokens.bridge];
489
+ const shareContext = ((main) => {
490
+ if (main instanceof Map) {
491
+ const testFn = main.get(tokens.testFn);
492
+ if (typeof testFn === 'function' && testFn() === tokens.testResult)
493
+ return true;
494
+ }
495
+ return false;
496
+ })(main);
497
+ const encryptedRandom = await BridgeUtilCrypto.aes.encrypt(data.content.random, tokens.validation);
498
+ if (shareContext) {
499
+ window.postMessage({
500
+ type: type.validation.receive,
501
+ content: {
502
+ encrypted: encryptedRandom,
503
+ shareContext
504
+ }
505
+ }, event.origin);
506
+ resolve(new BridgeDirect(main, true, tokens.directValidation));
507
+ }
508
+ else {
509
+ const channel = new MessageChannel();
510
+ const port1 = channel.port1;
511
+ window.postMessage({
512
+ type: type.validation.receive,
513
+ content: {
514
+ encrypted: encryptedRandom,
515
+ shareContext
516
+ }
517
+ }, event.origin, [channel.port2]);
518
+ resolve(await BridgeChannel.create(port1, true, tokens.portValidation));
519
+ }
520
+ });
521
+ });
522
+ return { certification: { tokens, type }, bridge };
523
+ },
524
+ connect: ({ tokens, type }) => {
525
+ return new Promise(async (resolve, reject) => {
526
+ const random = BridgeUtilCrypto.generateRandomHex();
527
+ const main = window[tokens.bridge] = new Map([[tokens.testFn, () => tokens.testResult]]);
528
+ const connectValidationRequest = setInterval(() => {
529
+ window.postMessage({
530
+ type: type.validation.request,
531
+ content: {
532
+ random
533
+ }
534
+ });
535
+ }, 100);
536
+ const connectValidationReceive = BridgeUtilListener.addEventListener(async (event) => {
537
+ const { data } = event;
538
+ if (data.type !== type.validation.receive)
539
+ return;
540
+ connectValidationReceive.removeEventListener();
541
+ clearInterval(connectValidationRequest);
542
+ const decryptedRandom = await BridgeUtilCrypto.aes.decrypt(data.content.encrypted, tokens.validation);
543
+ if (random !== decryptedRandom)
544
+ return reject(new BridgeConnectError("INVALID_VALIDATION", {
545
+ data: {
546
+ expected: [random],
547
+ received: decryptedRandom
548
+ }
549
+ }));
550
+ const shareContext = data.content.shareContext;
551
+ if (shareContext) {
552
+ resolve(new BridgeDirect(main, false, tokens.directValidation));
553
+ }
554
+ else {
555
+ const [port2] = event.ports;
556
+ if (!(port2 instanceof MessagePort))
557
+ return reject(new BridgeConnectError("INVALID_PORT", {
558
+ data: {
559
+ expected: ["MessagePort"],
560
+ received: port2
561
+ }
562
+ }));
563
+ resolve(await BridgeChannel.create(port2, false, tokens.portValidation));
564
+ }
565
+ });
566
+ });
567
+ }
568
+ };
569
+
570
+ exports.default = BridgeEntry;
571
+ //# sourceMappingURL=index.js.map