@subwallet/extension-base 0.6.7-1 → 0.6.7-2
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/background/KoniTypes.d.ts +64 -22
- package/background/KoniTypes.js +13 -23
- package/background/RequestBytesSign.js +1 -2
- package/background/RequestExtrinsicSign.js +1 -2
- package/background/handlers/Extension.js +28 -122
- package/background/handlers/State.js +28 -71
- package/background/handlers/Tabs.js +9 -45
- package/background/handlers/helpers.js +1 -1
- package/background/handlers/index.js +4 -2
- package/background/handlers/subscriptions.js +5 -2
- package/bundle.js +1 -0
- package/cjs/background/KoniTypes.js +15 -24
- package/cjs/background/RequestBytesSign.js +1 -6
- package/cjs/background/RequestExtrinsicSign.js +1 -4
- package/cjs/background/handlers/Extension.js +27 -174
- package/cjs/background/handlers/State.js +28 -82
- package/cjs/background/handlers/Tabs.js +9 -60
- package/cjs/background/handlers/helpers.js +1 -2
- package/cjs/background/handlers/index.js +4 -10
- package/cjs/background/handlers/subscriptions.js +5 -4
- package/cjs/bundle.js +0 -1
- package/cjs/defaults.js +1 -0
- package/cjs/detectOther.js +0 -4
- package/cjs/detectPackage.js +2 -4
- package/cjs/errors/SubWalletProviderError.js +1 -3
- package/cjs/index.js +0 -2
- package/cjs/packageInfo.js +3 -1
- package/cjs/page/Accounts.js +3 -6
- package/cjs/page/Injected.js +1 -8
- package/cjs/page/Metadata.js +1 -5
- package/cjs/page/PostMessageProvider.js +22 -38
- package/cjs/page/Signer.js +11 -11
- package/cjs/page/index.js +6 -13
- package/cjs/signers/substrates/LedgerSigner.js +1 -7
- package/cjs/signers/substrates/QrSigner.js +1 -10
- package/cjs/signers/web3/QrSigner.js +1 -12
- package/cjs/stores/Accounts.js +1 -8
- package/cjs/stores/Base.js +1 -15
- package/cjs/stores/Metadata.js +1 -6
- package/cjs/stores/index.js +0 -3
- package/cjs/utils/canDerive.js +1 -1
- package/cjs/utils/getId.js +1 -3
- package/cjs/utils/index.js +0 -1
- package/defaults.js +1 -0
- package/detectOther.js +1 -0
- package/detectPackage.js +2 -0
- package/errors/SubWalletProviderError.js +1 -1
- package/index.js +2 -0
- package/package.json +4 -4
- package/packageInfo.js +3 -1
- package/page/Accounts.js +3 -4
- package/page/Injected.js +1 -1
- package/page/Metadata.js +1 -3
- package/page/PostMessageProvider.js +22 -33
- package/page/Signer.js +11 -9
- package/page/index.js +8 -6
- package/signers/substrates/LedgerSigner.js +1 -3
- package/signers/substrates/QrSigner.js +1 -5
- package/signers/web3/QrSigner.js +1 -5
- package/stores/Accounts.js +1 -3
- package/stores/Base.js +1 -13
- package/stores/Metadata.js +1 -1
- package/stores/index.js +1 -0
- package/utils/canDerive.js +1 -0
- package/utils/getId.js +1 -0
- package/utils/index.js +1 -0
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
// Copyright 2019-2022 @polkadot/extension-bg authors & contributors
|
|
2
2
|
// SPDX-License-Identifier: Apache-2.0
|
|
3
|
+
|
|
3
4
|
import { getId } from '@subwallet/extension-base/utils/getId';
|
|
4
5
|
import { addMetadata, knownMetadata } from '@subwallet/extension-chains';
|
|
5
6
|
import { BehaviorSubject } from 'rxjs';
|
|
@@ -22,15 +23,12 @@ const NORMAL_WINDOW_OPTS = {
|
|
|
22
23
|
url: NOTIFICATION_URL
|
|
23
24
|
};
|
|
24
25
|
export let NotificationOptions;
|
|
25
|
-
|
|
26
26
|
(function (NotificationOptions) {
|
|
27
27
|
NotificationOptions[NotificationOptions["None"] = 0] = "None";
|
|
28
28
|
NotificationOptions[NotificationOptions["Normal"] = 1] = "Normal";
|
|
29
29
|
NotificationOptions[NotificationOptions["PopUp"] = 2] = "PopUp";
|
|
30
30
|
})(NotificationOptions || (NotificationOptions = {}));
|
|
31
|
-
|
|
32
31
|
const AUTH_URLS_KEY = 'authUrls';
|
|
33
|
-
|
|
34
32
|
function extractMetadata(store) {
|
|
35
33
|
store.allMap(map => {
|
|
36
34
|
const knownEntries = Object.entries(knownGenesis);
|
|
@@ -38,18 +36,17 @@ function extractMetadata(store) {
|
|
|
38
36
|
const removals = [];
|
|
39
37
|
Object.entries(map).forEach(([key, def]) => {
|
|
40
38
|
const entry = knownEntries.find(([, hashes]) => hashes.includes(def.genesisHash));
|
|
41
|
-
|
|
42
39
|
if (entry) {
|
|
43
40
|
const [name, hashes] = entry;
|
|
44
|
-
const index = hashes.indexOf(def.genesisHash);
|
|
45
|
-
// (lower is better/newer)
|
|
41
|
+
const index = hashes.indexOf(def.genesisHash);
|
|
46
42
|
|
|
43
|
+
// flatten the known metadata based on the genesis index
|
|
44
|
+
// (lower is better/newer)
|
|
47
45
|
if (!defs[name] || defs[name].index > index) {
|
|
48
46
|
if (defs[name]) {
|
|
49
47
|
// remove the old version of the metadata
|
|
50
48
|
removals.push(defs[name].key);
|
|
51
49
|
}
|
|
52
|
-
|
|
53
50
|
defs[name] = {
|
|
54
51
|
def,
|
|
55
52
|
index,
|
|
@@ -71,48 +68,44 @@ function extractMetadata(store) {
|
|
|
71
68
|
}) => addMetadata(def));
|
|
72
69
|
});
|
|
73
70
|
}
|
|
74
|
-
|
|
75
71
|
export default class State {
|
|
76
72
|
#authUrls = {};
|
|
77
73
|
#authRequests = {};
|
|
78
|
-
#metaStore = new MetadataStore();
|
|
74
|
+
#metaStore = new MetadataStore();
|
|
79
75
|
|
|
76
|
+
// Map of providers currently injected in tabs
|
|
80
77
|
#injectedProviders = new Map();
|
|
81
78
|
#metaRequests = {};
|
|
82
|
-
#notification = settings.notification;
|
|
79
|
+
#notification = settings.notification;
|
|
83
80
|
|
|
81
|
+
// Map of all providers exposed by the extension, they are retrievable by key
|
|
84
82
|
#providers;
|
|
85
83
|
#signRequests = {};
|
|
86
84
|
#windows = [];
|
|
87
85
|
authSubject = new BehaviorSubject([]);
|
|
88
86
|
metaSubject = new BehaviorSubject([]);
|
|
89
87
|
signSubject = new BehaviorSubject([]);
|
|
90
|
-
|
|
91
88
|
constructor(providers = {}) {
|
|
92
89
|
this.#providers = providers;
|
|
93
|
-
extractMetadata(this.#metaStore);
|
|
90
|
+
extractMetadata(this.#metaStore);
|
|
94
91
|
|
|
92
|
+
// retrieve previously set authorizations
|
|
95
93
|
const authString = localStorage.getItem(AUTH_URLS_KEY) || '{}';
|
|
96
94
|
const previousAuth = JSON.parse(authString);
|
|
97
95
|
this.#authUrls = previousAuth;
|
|
98
96
|
}
|
|
99
|
-
|
|
100
97
|
get knownMetadata() {
|
|
101
98
|
return knownMetadata();
|
|
102
99
|
}
|
|
103
|
-
|
|
104
100
|
get numAuthRequests() {
|
|
105
101
|
return Object.keys(this.#authRequests).length;
|
|
106
102
|
}
|
|
107
|
-
|
|
108
103
|
get numMetaRequests() {
|
|
109
104
|
return Object.keys(this.#metaRequests).length;
|
|
110
105
|
}
|
|
111
|
-
|
|
112
106
|
get numSignRequests() {
|
|
113
107
|
return Object.keys(this.#signRequests).length;
|
|
114
108
|
}
|
|
115
|
-
|
|
116
109
|
get allAuthRequests() {
|
|
117
110
|
return Object.values(this.#authRequests).map(({
|
|
118
111
|
id,
|
|
@@ -124,7 +117,6 @@ export default class State {
|
|
|
124
117
|
url
|
|
125
118
|
}));
|
|
126
119
|
}
|
|
127
|
-
|
|
128
120
|
get allMetaRequests() {
|
|
129
121
|
return Object.values(this.#metaRequests).map(({
|
|
130
122
|
id,
|
|
@@ -136,7 +128,6 @@ export default class State {
|
|
|
136
128
|
url
|
|
137
129
|
}));
|
|
138
130
|
}
|
|
139
|
-
|
|
140
131
|
get allSignRequests() {
|
|
141
132
|
return Object.values(this.#signRequests).map(({
|
|
142
133
|
account,
|
|
@@ -150,20 +141,16 @@ export default class State {
|
|
|
150
141
|
url
|
|
151
142
|
}));
|
|
152
143
|
}
|
|
153
|
-
|
|
154
144
|
get authUrls() {
|
|
155
145
|
return this.#authUrls;
|
|
156
146
|
}
|
|
157
|
-
|
|
158
147
|
getPopup() {
|
|
159
148
|
return this.#windows;
|
|
160
149
|
}
|
|
161
|
-
|
|
162
150
|
popupClose() {
|
|
163
151
|
this.#windows.forEach(id => withErrorLog(() => chrome.windows.remove(id)));
|
|
164
152
|
this.#windows = [];
|
|
165
153
|
}
|
|
166
|
-
|
|
167
154
|
popupOpen() {
|
|
168
155
|
if (this.#notification !== 'extension') {
|
|
169
156
|
if (this.#notification === 'window') {
|
|
@@ -173,16 +160,14 @@ export default class State {
|
|
|
173
160
|
}
|
|
174
161
|
});
|
|
175
162
|
}
|
|
176
|
-
|
|
177
163
|
chrome.windows.getCurrent(win => {
|
|
178
|
-
const popupOptions = {
|
|
164
|
+
const popupOptions = {
|
|
165
|
+
...POPUP_WINDOW_OPTS
|
|
179
166
|
};
|
|
180
|
-
|
|
181
167
|
if (win) {
|
|
182
168
|
popupOptions.left = (win.left || 0) + (win.width || 0) - (POPUP_WINDOW_OPTS.width || 0) - 20;
|
|
183
169
|
popupOptions.top = (win.top || 0) + 80;
|
|
184
170
|
}
|
|
185
|
-
|
|
186
171
|
chrome.windows.create(popupOptions, window => {
|
|
187
172
|
if (window) {
|
|
188
173
|
this.#windows.push(window.id || 0);
|
|
@@ -191,7 +176,6 @@ export default class State {
|
|
|
191
176
|
});
|
|
192
177
|
}
|
|
193
178
|
}
|
|
194
|
-
|
|
195
179
|
authComplete = (id, resolve, reject) => {
|
|
196
180
|
const complete = result => {
|
|
197
181
|
const isAllowed = result === true;
|
|
@@ -215,7 +199,6 @@ export default class State {
|
|
|
215
199
|
delete this.#authRequests[id];
|
|
216
200
|
this.updateIconAuth(true);
|
|
217
201
|
};
|
|
218
|
-
|
|
219
202
|
return {
|
|
220
203
|
reject: error => {
|
|
221
204
|
complete(error);
|
|
@@ -227,17 +210,14 @@ export default class State {
|
|
|
227
210
|
}
|
|
228
211
|
};
|
|
229
212
|
};
|
|
230
|
-
|
|
231
213
|
saveCurrentAuthList() {
|
|
232
214
|
localStorage.setItem(AUTH_URLS_KEY, JSON.stringify(this.#authUrls));
|
|
233
215
|
}
|
|
234
|
-
|
|
235
216
|
metaComplete = (id, resolve, reject) => {
|
|
236
217
|
const complete = () => {
|
|
237
218
|
delete this.#metaRequests[id];
|
|
238
219
|
this.updateIconMeta(true);
|
|
239
220
|
};
|
|
240
|
-
|
|
241
221
|
return {
|
|
242
222
|
reject: error => {
|
|
243
223
|
complete();
|
|
@@ -254,7 +234,6 @@ export default class State {
|
|
|
254
234
|
delete this.#signRequests[id];
|
|
255
235
|
this.updateIconSign(true);
|
|
256
236
|
};
|
|
257
|
-
|
|
258
237
|
return {
|
|
259
238
|
reject: error => {
|
|
260
239
|
complete();
|
|
@@ -266,13 +245,11 @@ export default class State {
|
|
|
266
245
|
}
|
|
267
246
|
};
|
|
268
247
|
};
|
|
269
|
-
|
|
270
248
|
stripUrl(url) {
|
|
271
249
|
assert(url && (url.startsWith('http:') || url.startsWith('https:') || url.startsWith('ipfs:') || url.startsWith('ipns:')), `Invalid url ${url}, expected to start with http: or https: or ipfs: or ipns:`);
|
|
272
250
|
const parts = url.split('/');
|
|
273
251
|
return parts[2];
|
|
274
252
|
}
|
|
275
|
-
|
|
276
253
|
updateIcon(shouldClose) {
|
|
277
254
|
const authCount = this.numAuthRequests;
|
|
278
255
|
const metaCount = this.numMetaRequests;
|
|
@@ -281,12 +258,10 @@ export default class State {
|
|
|
281
258
|
withErrorLog(() => chrome.browserAction.setBadgeText({
|
|
282
259
|
text
|
|
283
260
|
}));
|
|
284
|
-
|
|
285
261
|
if (shouldClose && text === '') {
|
|
286
262
|
this.popupClose();
|
|
287
263
|
}
|
|
288
264
|
}
|
|
289
|
-
|
|
290
265
|
toggleAuthorization(url) {
|
|
291
266
|
const entry = this.#authUrls[url];
|
|
292
267
|
assert(entry, `The source ${url} is not known`);
|
|
@@ -294,37 +269,33 @@ export default class State {
|
|
|
294
269
|
this.saveCurrentAuthList();
|
|
295
270
|
return this.#authUrls;
|
|
296
271
|
}
|
|
297
|
-
|
|
298
272
|
updateIconAuth(shouldClose) {
|
|
299
273
|
this.authSubject.next(this.allAuthRequests);
|
|
300
274
|
this.updateIcon(shouldClose);
|
|
301
275
|
}
|
|
302
|
-
|
|
303
276
|
updateIconMeta(shouldClose) {
|
|
304
277
|
this.metaSubject.next(this.allMetaRequests);
|
|
305
278
|
this.updateIcon(shouldClose);
|
|
306
279
|
}
|
|
307
|
-
|
|
308
280
|
updateIconSign(shouldClose) {
|
|
309
281
|
this.signSubject.next(this.allSignRequests);
|
|
310
282
|
this.updateIcon(shouldClose);
|
|
311
283
|
}
|
|
312
|
-
|
|
313
284
|
async authorizeUrl(url, request) {
|
|
314
|
-
const idStr = this.stripUrl(url);
|
|
285
|
+
const idStr = this.stripUrl(url);
|
|
315
286
|
|
|
287
|
+
// Do not enqueue duplicate authorization requests.
|
|
316
288
|
const isDuplicate = Object.values(this.#authRequests).some(request => request.idStr === idStr);
|
|
317
289
|
assert(!isDuplicate, `The source ${url} has a pending authorization request`);
|
|
318
|
-
|
|
319
290
|
if (this.#authUrls[idStr]) {
|
|
320
291
|
// this url was seen in the past
|
|
321
292
|
assert(this.#authUrls[idStr].isAllowed, `The source ${url} is not allowed to interact with this extension`);
|
|
322
293
|
return false;
|
|
323
294
|
}
|
|
324
|
-
|
|
325
295
|
return new Promise((resolve, reject) => {
|
|
326
296
|
const id = getId();
|
|
327
|
-
this.#authRequests[id] = {
|
|
297
|
+
this.#authRequests[id] = {
|
|
298
|
+
...this.authComplete(id, resolve, reject),
|
|
328
299
|
id,
|
|
329
300
|
idStr,
|
|
330
301
|
request,
|
|
@@ -334,18 +305,17 @@ export default class State {
|
|
|
334
305
|
this.popupOpen();
|
|
335
306
|
});
|
|
336
307
|
}
|
|
337
|
-
|
|
338
308
|
ensureUrlAuthorized(url) {
|
|
339
309
|
const entry = this.#authUrls[this.stripUrl(url)];
|
|
340
310
|
assert(entry, `The source ${url} has not been enabled yet`);
|
|
341
311
|
assert(entry.isAllowed, `The source ${url} is not allowed to interact with this extension`);
|
|
342
312
|
return true;
|
|
343
313
|
}
|
|
344
|
-
|
|
345
314
|
injectMetadata(url, request) {
|
|
346
315
|
return new Promise((resolve, reject) => {
|
|
347
316
|
const id = getId();
|
|
348
|
-
this.#metaRequests[id] = {
|
|
317
|
+
this.#metaRequests[id] = {
|
|
318
|
+
...this.metaComplete(id, resolve, reject),
|
|
349
319
|
id,
|
|
350
320
|
request,
|
|
351
321
|
url
|
|
@@ -354,56 +324,49 @@ export default class State {
|
|
|
354
324
|
this.popupOpen();
|
|
355
325
|
});
|
|
356
326
|
}
|
|
357
|
-
|
|
358
327
|
getAuthRequest(id) {
|
|
359
328
|
return this.#authRequests[id];
|
|
360
329
|
}
|
|
361
|
-
|
|
362
330
|
getMetaRequest(id) {
|
|
363
331
|
return this.#metaRequests[id];
|
|
364
332
|
}
|
|
365
|
-
|
|
366
333
|
getSignRequest(id) {
|
|
367
334
|
return this.#signRequests[id];
|
|
368
|
-
}
|
|
369
|
-
|
|
335
|
+
}
|
|
370
336
|
|
|
337
|
+
// List all providers the extension is exposing
|
|
371
338
|
rpcListProviders() {
|
|
372
339
|
return Promise.resolve(Object.keys(this.#providers).reduce((acc, key) => {
|
|
373
340
|
acc[key] = this.#providers[key].meta;
|
|
374
341
|
return acc;
|
|
375
342
|
}, {}));
|
|
376
343
|
}
|
|
377
|
-
|
|
378
344
|
rpcSend(request, port) {
|
|
379
345
|
const provider = this.#injectedProviders.get(port);
|
|
380
346
|
assert(provider, 'Cannot call pub(rpc.subscribe) before provider is set');
|
|
381
347
|
return provider.send(request.method, request.params);
|
|
382
|
-
}
|
|
383
|
-
|
|
348
|
+
}
|
|
384
349
|
|
|
350
|
+
// Start a provider, return its meta
|
|
385
351
|
rpcStartProvider(key, port) {
|
|
386
352
|
assert(Object.keys(this.#providers).includes(key), `Provider ${key} is not exposed by extension`);
|
|
387
|
-
|
|
388
353
|
if (this.#injectedProviders.get(port)) {
|
|
389
354
|
return Promise.resolve(this.#providers[key].meta);
|
|
390
|
-
}
|
|
391
|
-
|
|
355
|
+
}
|
|
392
356
|
|
|
393
|
-
|
|
357
|
+
// Instantiate the provider
|
|
358
|
+
this.#injectedProviders.set(port, this.#providers[key].start());
|
|
394
359
|
|
|
360
|
+
// Close provider connection when page is closed
|
|
395
361
|
port.onDisconnect.addListener(() => {
|
|
396
362
|
const provider = this.#injectedProviders.get(port);
|
|
397
|
-
|
|
398
363
|
if (provider) {
|
|
399
364
|
withErrorLog(() => provider.disconnect());
|
|
400
365
|
}
|
|
401
|
-
|
|
402
366
|
this.#injectedProviders.delete(port);
|
|
403
367
|
});
|
|
404
368
|
return Promise.resolve(this.#providers[key].meta);
|
|
405
369
|
}
|
|
406
|
-
|
|
407
370
|
rpcSubscribe({
|
|
408
371
|
method,
|
|
409
372
|
params,
|
|
@@ -413,36 +376,31 @@ export default class State {
|
|
|
413
376
|
assert(provider, 'Cannot call pub(rpc.subscribe) before provider is set');
|
|
414
377
|
return provider.subscribe(type, method, params, cb);
|
|
415
378
|
}
|
|
416
|
-
|
|
417
379
|
rpcSubscribeConnected(_request, cb, port) {
|
|
418
380
|
const provider = this.#injectedProviders.get(port);
|
|
419
381
|
assert(provider, 'Cannot call pub(rpc.subscribeConnected) before provider is set');
|
|
420
382
|
cb(null, provider.isConnected); // Immediately send back current isConnected
|
|
421
|
-
|
|
422
383
|
provider.on('connected', () => cb(null, true));
|
|
423
384
|
provider.on('disconnected', () => cb(null, false));
|
|
424
385
|
}
|
|
425
|
-
|
|
426
386
|
rpcUnsubscribe(request, port) {
|
|
427
387
|
const provider = this.#injectedProviders.get(port);
|
|
428
388
|
assert(provider, 'Cannot call pub(rpc.unsubscribe) before provider is set');
|
|
429
389
|
return provider.unsubscribe(request.type, request.method, request.subscriptionId);
|
|
430
390
|
}
|
|
431
|
-
|
|
432
391
|
saveMetadata(meta) {
|
|
433
392
|
this.#metaStore.set(meta.genesisHash, meta);
|
|
434
393
|
addMetadata(meta);
|
|
435
394
|
}
|
|
436
|
-
|
|
437
395
|
setNotification(notification) {
|
|
438
396
|
this.#notification = notification;
|
|
439
397
|
return true;
|
|
440
398
|
}
|
|
441
|
-
|
|
442
399
|
sign(url, request, account) {
|
|
443
400
|
const id = getId();
|
|
444
401
|
return new Promise((resolve, reject) => {
|
|
445
|
-
this.#signRequests[id] = {
|
|
402
|
+
this.#signRequests[id] = {
|
|
403
|
+
...this.signComplete(id, resolve, reject),
|
|
446
404
|
account,
|
|
447
405
|
id,
|
|
448
406
|
request,
|
|
@@ -452,5 +410,4 @@ export default class State {
|
|
|
452
410
|
this.popupOpen();
|
|
453
411
|
});
|
|
454
412
|
}
|
|
455
|
-
|
|
456
413
|
}
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
// Copyright 2019-2022 @polkadot/extension authors & contributors
|
|
2
2
|
// SPDX-License-Identifier: Apache-2.0
|
|
3
|
+
|
|
3
4
|
import { PHISHING_PAGE_REDIRECT } from '@subwallet/extension-base/defaults';
|
|
4
5
|
import { canDerive } from '@subwallet/extension-base/utils';
|
|
5
6
|
import { checkIfDenied } from '@polkadot/phishing';
|
|
@@ -10,7 +11,6 @@ import RequestBytesSign from "../RequestBytesSign.js";
|
|
|
10
11
|
import RequestExtrinsicSign from "../RequestExtrinsicSign.js";
|
|
11
12
|
import { withErrorLog } from "./helpers.js";
|
|
12
13
|
import { createSubscription, unsubscribe } from "./subscriptions.js";
|
|
13
|
-
|
|
14
14
|
function transformAccounts(accounts, anyType = false) {
|
|
15
15
|
return Object.values(accounts).filter(({
|
|
16
16
|
json: {
|
|
@@ -39,26 +39,23 @@ function transformAccounts(accounts, anyType = false) {
|
|
|
39
39
|
type
|
|
40
40
|
}));
|
|
41
41
|
}
|
|
42
|
-
|
|
43
42
|
export default class Tabs {
|
|
44
43
|
#state;
|
|
45
|
-
|
|
46
44
|
constructor(state) {
|
|
47
45
|
this.#state = state;
|
|
48
46
|
}
|
|
49
|
-
|
|
50
47
|
authorize(url, request) {
|
|
51
48
|
return this.#state.authorizeUrl(url, request);
|
|
52
|
-
}
|
|
53
|
-
|
|
49
|
+
}
|
|
54
50
|
|
|
51
|
+
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
55
52
|
accountsList(url, {
|
|
56
53
|
anyType
|
|
57
54
|
}) {
|
|
58
55
|
return transformAccounts(accountsObservable.subject.getValue(), anyType);
|
|
59
|
-
}
|
|
60
|
-
|
|
56
|
+
}
|
|
61
57
|
|
|
58
|
+
// FIXME This looks very much like what we have in Extension
|
|
62
59
|
accountsSubscribe(url, id, port) {
|
|
63
60
|
const cb = createSubscription(id, port);
|
|
64
61
|
const subscription = accountsObservable.subject.subscribe(accounts => cb(transformAccounts(accounts)));
|
|
@@ -68,13 +65,11 @@ export default class Tabs {
|
|
|
68
65
|
});
|
|
69
66
|
return true;
|
|
70
67
|
}
|
|
71
|
-
|
|
72
68
|
getSigningPair(address) {
|
|
73
69
|
const pair = keyring.getPair(address);
|
|
74
70
|
assert(pair, 'Unable to find keypair');
|
|
75
71
|
return pair;
|
|
76
72
|
}
|
|
77
|
-
|
|
78
73
|
bytesSign(url, request) {
|
|
79
74
|
const address = request.address;
|
|
80
75
|
const pair = this.getSigningPair(address);
|
|
@@ -83,7 +78,6 @@ export default class Tabs {
|
|
|
83
78
|
...pair.meta
|
|
84
79
|
});
|
|
85
80
|
}
|
|
86
|
-
|
|
87
81
|
extrinsicSign(url, request) {
|
|
88
82
|
const address = request.address;
|
|
89
83
|
const pair = this.getSigningPair(address);
|
|
@@ -92,12 +86,11 @@ export default class Tabs {
|
|
|
92
86
|
...pair.meta
|
|
93
87
|
});
|
|
94
88
|
}
|
|
95
|
-
|
|
96
89
|
metadataProvide(url, request) {
|
|
97
90
|
return this.#state.injectMetadata(url, request);
|
|
98
|
-
}
|
|
99
|
-
|
|
91
|
+
}
|
|
100
92
|
|
|
93
|
+
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
101
94
|
metadataList(url) {
|
|
102
95
|
return this.#state.knownMetadata.map(({
|
|
103
96
|
genesisHash,
|
|
@@ -107,50 +100,40 @@ export default class Tabs {
|
|
|
107
100
|
specVersion
|
|
108
101
|
}));
|
|
109
102
|
}
|
|
110
|
-
|
|
111
103
|
rpcListProviders() {
|
|
112
104
|
return this.#state.rpcListProviders();
|
|
113
105
|
}
|
|
114
|
-
|
|
115
106
|
rpcSend(request, port) {
|
|
116
107
|
return this.#state.rpcSend(request, port);
|
|
117
108
|
}
|
|
118
|
-
|
|
119
109
|
rpcStartProvider(key, port) {
|
|
120
110
|
return this.#state.rpcStartProvider(key, port);
|
|
121
111
|
}
|
|
122
|
-
|
|
123
112
|
async rpcSubscribe(request, id, port) {
|
|
124
113
|
const innerCb = createSubscription(id, port);
|
|
125
|
-
|
|
126
114
|
const cb = (_error, data) => innerCb(data);
|
|
127
|
-
|
|
128
115
|
const subscriptionId = await this.#state.rpcSubscribe(request, cb, port);
|
|
129
116
|
port.onDisconnect.addListener(() => {
|
|
130
117
|
unsubscribe(id);
|
|
131
|
-
withErrorLog(() => this.rpcUnsubscribe({
|
|
118
|
+
withErrorLog(() => this.rpcUnsubscribe({
|
|
119
|
+
...request,
|
|
132
120
|
subscriptionId
|
|
133
121
|
}, port));
|
|
134
122
|
});
|
|
135
123
|
return true;
|
|
136
124
|
}
|
|
137
|
-
|
|
138
125
|
rpcSubscribeConnected(request, id, port) {
|
|
139
126
|
const innerCb = createSubscription(id, port);
|
|
140
|
-
|
|
141
127
|
const cb = (_error, data) => innerCb(data);
|
|
142
|
-
|
|
143
128
|
this.#state.rpcSubscribeConnected(request, cb, port);
|
|
144
129
|
port.onDisconnect.addListener(() => {
|
|
145
130
|
unsubscribe(id);
|
|
146
131
|
});
|
|
147
132
|
return Promise.resolve(true);
|
|
148
133
|
}
|
|
149
|
-
|
|
150
134
|
async rpcUnsubscribe(request, port) {
|
|
151
135
|
return this.#state.rpcUnsubscribe(request, port);
|
|
152
136
|
}
|
|
153
|
-
|
|
154
137
|
redirectPhishingLanding(phishingWebsite) {
|
|
155
138
|
const nonFragment = phishingWebsite.split('#')[0];
|
|
156
139
|
const encodedWebsite = encodeURIComponent(nonFragment);
|
|
@@ -165,66 +148,47 @@ export default class Tabs {
|
|
|
165
148
|
})));
|
|
166
149
|
});
|
|
167
150
|
}
|
|
168
|
-
|
|
169
151
|
async redirectIfPhishing(url) {
|
|
170
152
|
const isInDenyList = await checkIfDenied(url);
|
|
171
|
-
|
|
172
153
|
if (isInDenyList) {
|
|
173
154
|
this.redirectPhishingLanding(url);
|
|
174
155
|
return true;
|
|
175
156
|
}
|
|
176
|
-
|
|
177
157
|
return false;
|
|
178
158
|
}
|
|
179
|
-
|
|
180
159
|
async handle(id, type, request, url, port) {
|
|
181
160
|
if (type === 'pub(phishing.redirectIfDenied)') {
|
|
182
161
|
return this.redirectIfPhishing(url);
|
|
183
162
|
}
|
|
184
|
-
|
|
185
163
|
switch (type) {
|
|
186
164
|
case 'pub(authorize.tab)':
|
|
187
165
|
return this.authorize(url, request);
|
|
188
|
-
|
|
189
166
|
case 'pub(accounts.list)':
|
|
190
167
|
return this.accountsList(url, request);
|
|
191
|
-
|
|
192
168
|
case 'pub(accounts.subscribe)':
|
|
193
169
|
return this.accountsSubscribe(url, id, port);
|
|
194
|
-
|
|
195
170
|
case 'pub(bytes.sign)':
|
|
196
171
|
return this.bytesSign(url, request);
|
|
197
|
-
|
|
198
172
|
case 'pub(extrinsic.sign)':
|
|
199
173
|
return this.extrinsicSign(url, request);
|
|
200
|
-
|
|
201
174
|
case 'pub(metadata.list)':
|
|
202
175
|
return this.metadataList(url);
|
|
203
|
-
|
|
204
176
|
case 'pub(metadata.provide)':
|
|
205
177
|
return this.metadataProvide(url, request);
|
|
206
|
-
|
|
207
178
|
case 'pub(rpc.listProviders)':
|
|
208
179
|
return this.rpcListProviders();
|
|
209
|
-
|
|
210
180
|
case 'pub(rpc.send)':
|
|
211
181
|
return this.rpcSend(request, port);
|
|
212
|
-
|
|
213
182
|
case 'pub(rpc.startProvider)':
|
|
214
183
|
return this.rpcStartProvider(request, port);
|
|
215
|
-
|
|
216
184
|
case 'pub(rpc.subscribe)':
|
|
217
185
|
return this.rpcSubscribe(request, id, port);
|
|
218
|
-
|
|
219
186
|
case 'pub(rpc.subscribeConnected)':
|
|
220
187
|
return this.rpcSubscribeConnected(request, id, port);
|
|
221
|
-
|
|
222
188
|
case 'pub(rpc.unsubscribe)':
|
|
223
189
|
return this.rpcUnsubscribe(request, port);
|
|
224
|
-
|
|
225
190
|
default:
|
|
226
191
|
throw new Error(`Unable to handle message of type ${type}`);
|
|
227
192
|
}
|
|
228
193
|
}
|
|
229
|
-
|
|
230
194
|
}
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
// Copyright 2019-2022 @polkadot/extension authors & contributors
|
|
2
2
|
// SPDX-License-Identifier: Apache-2.0
|
|
3
|
+
|
|
3
4
|
export function withErrorLog(fn) {
|
|
4
5
|
try {
|
|
5
6
|
const p = fn();
|
|
6
|
-
|
|
7
7
|
if (p && typeof p === 'object' && typeof p.catch === 'function') {
|
|
8
8
|
p.catch(console.error);
|
|
9
9
|
}
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
// Copyright 2019-2022 @polkadot/extension authors & contributors
|
|
2
2
|
// SPDX-License-Identifier: Apache-2.0
|
|
3
|
+
|
|
3
4
|
import { assert } from '@polkadot/util';
|
|
4
5
|
import { PORT_EXTENSION } from "../../defaults.js";
|
|
5
6
|
import Extension from "./Extension.js";
|
|
@@ -22,17 +23,18 @@ export default function handler({
|
|
|
22
23
|
const promise = isExtension ? extension.handle(id, message, request, port) : tabs.handle(id, message, request, from, port);
|
|
23
24
|
promise.then(response => {
|
|
24
25
|
console.log(`[out] ${source}`); // :: ${JSON.stringify(response)}`);
|
|
26
|
+
|
|
25
27
|
// between the start and the end of the promise, the user may have closed
|
|
26
28
|
// the tab, in which case port will be undefined
|
|
27
|
-
|
|
28
29
|
assert(port, 'Port has been disconnected');
|
|
29
30
|
port.postMessage({
|
|
30
31
|
id,
|
|
31
32
|
response
|
|
32
33
|
});
|
|
33
34
|
}).catch(error => {
|
|
34
|
-
console.log(`[err] ${source}:: ${error.message}`);
|
|
35
|
+
console.log(`[err] ${source}:: ${error.message}`);
|
|
35
36
|
|
|
37
|
+
// only send message back to port if it's still connected
|
|
36
38
|
if (port) {
|
|
37
39
|
port.postMessage({
|
|
38
40
|
error: error.message,
|
|
@@ -1,7 +1,9 @@
|
|
|
1
1
|
// Copyright 2019-2022 @polkadot/extension authors & contributors
|
|
2
2
|
// SPDX-License-Identifier: Apache-2.0
|
|
3
|
-
const subscriptions = {}; // return a subscription callback, that will send the data to the caller via the port
|
|
4
3
|
|
|
4
|
+
const subscriptions = {};
|
|
5
|
+
|
|
6
|
+
// return a subscription callback, that will send the data to the caller via the port
|
|
5
7
|
export function createSubscription(id, port) {
|
|
6
8
|
subscriptions[id] = port;
|
|
7
9
|
return subscription => {
|
|
@@ -15,8 +17,9 @@ export function createSubscription(id, port) {
|
|
|
15
17
|
}
|
|
16
18
|
export function isSubscriptionRunning(id) {
|
|
17
19
|
return !!subscriptions[id];
|
|
18
|
-
}
|
|
20
|
+
}
|
|
19
21
|
|
|
22
|
+
// clear a previous subscriber
|
|
20
23
|
export function unsubscribe(id) {
|
|
21
24
|
if (subscriptions[id]) {
|
|
22
25
|
console.log(`Unsubscribing from ${id}`);
|
package/bundle.js
CHANGED