@polkadot/extension-base 0.44.9 → 0.45.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.
Files changed (58) hide show
  1. package/background/RequestBytesSign.js +9 -11
  2. package/background/RequestExtrinsicSign.js +9 -11
  3. package/background/handlers/Extension.js +456 -611
  4. package/background/handlers/State.js +374 -421
  5. package/background/handlers/Tabs.js +174 -211
  6. package/background/handlers/helpers.js +8 -10
  7. package/background/handlers/index.js +29 -39
  8. package/background/handlers/subscriptions.js +13 -22
  9. package/bundle.js +1 -4
  10. package/cjs/background/RequestBytesSign.js +11 -18
  11. package/cjs/background/RequestExtrinsicSign.js +9 -16
  12. package/cjs/background/handlers/Extension.js +468 -658
  13. package/cjs/background/handlers/State.js +389 -460
  14. package/cjs/background/handlers/Tabs.js +185 -242
  15. package/cjs/background/handlers/helpers.js +12 -16
  16. package/cjs/background/handlers/index.js +37 -52
  17. package/cjs/background/handlers/subscriptions.js +17 -28
  18. package/cjs/background/types.js +2 -1
  19. package/cjs/bundle.js +4 -11
  20. package/cjs/defaults.js +3 -12
  21. package/cjs/detectOther.js +5 -12
  22. package/cjs/detectPackage.js +6 -11
  23. package/cjs/index.js +3 -15
  24. package/cjs/packageInfo.js +2 -16
  25. package/cjs/page/Accounts.js +19 -28
  26. package/cjs/page/Injected.js +19 -26
  27. package/cjs/page/Metadata.js +10 -18
  28. package/cjs/page/PostMessageProvider.js +127 -160
  29. package/cjs/page/Signer.js +23 -38
  30. package/cjs/page/index.js +44 -61
  31. package/cjs/page/types.js +2 -1
  32. package/cjs/stores/Accounts.js +17 -22
  33. package/cjs/stores/Base.js +56 -63
  34. package/cjs/stores/Metadata.js +10 -15
  35. package/cjs/stores/index.js +9 -19
  36. package/cjs/types.js +2 -1
  37. package/cjs/utils/canDerive.js +5 -10
  38. package/cjs/utils/getId.js +6 -11
  39. package/cjs/utils/index.js +4 -11
  40. package/defaults.js +1 -8
  41. package/detectOther.js +0 -3
  42. package/detectPackage.js +2 -7
  43. package/index.js +1 -7
  44. package/package.json +20 -17
  45. package/packageInfo.js +1 -11
  46. package/page/Accounts.js +18 -23
  47. package/page/Injected.js +19 -18
  48. package/page/Metadata.js +9 -13
  49. package/page/PostMessageProvider.js +118 -149
  50. package/page/Signer.js +22 -33
  51. package/page/index.js +36 -59
  52. package/stores/Accounts.js +14 -15
  53. package/stores/Base.js +51 -56
  54. package/stores/Metadata.js +7 -8
  55. package/stores/index.js +2 -5
  56. package/utils/canDerive.js +1 -4
  57. package/utils/getId.js +2 -5
  58. package/utils/index.js +1 -4
@@ -1,668 +1,478 @@
1
1
  "use strict";
2
-
3
- var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
4
- Object.defineProperty(exports, "__esModule", {
5
- value: true
6
- });
7
- exports.default = void 0;
8
- var _defaults = require("@polkadot/extension-base/defaults");
9
- var _extensionChains = require("@polkadot/extension-chains");
10
- var _types = require("@polkadot/types");
11
- var _uiKeyring = _interopRequireDefault(require("@polkadot/ui-keyring"));
12
- var _accounts = require("@polkadot/ui-keyring/observable/accounts");
13
- var _util = require("@polkadot/util");
14
- var _utilCrypto = require("@polkadot/util-crypto");
15
- var _helpers = require("./helpers");
16
- var _subscriptions = require("./subscriptions");
17
- // Copyright 2019-2023 @polkadot/extension authors & contributors
18
- // SPDX-License-Identifier: Apache-2.0
19
-
2
+ var _Extension_cachedUnlocks, _Extension_state;
3
+ Object.defineProperty(exports, "__esModule", { value: true });
4
+ const tslib_1 = require("tslib");
5
+ const defaults_1 = require("@polkadot/extension-base/defaults");
6
+ const extension_chains_1 = require("@polkadot/extension-chains");
7
+ const types_1 = require("@polkadot/types");
8
+ const ui_keyring_1 = tslib_1.__importDefault(require("@polkadot/ui-keyring"));
9
+ const accounts_1 = require("@polkadot/ui-keyring/observable/accounts");
10
+ const util_1 = require("@polkadot/util");
11
+ const util_crypto_1 = require("@polkadot/util-crypto");
12
+ const helpers_1 = require("./helpers");
13
+ const subscriptions_1 = require("./subscriptions");
20
14
  const SEED_DEFAULT_LENGTH = 12;
21
15
  const SEED_LENGTHS = [12, 15, 18, 21, 24];
22
16
  const ETH_DERIVE_DEFAULT = "/m/44'/60'/0'/0/0";
23
17
  function getSuri(seed, type) {
24
- return type === 'ethereum' ? `${seed}${ETH_DERIVE_DEFAULT}` : seed;
18
+ return type === 'ethereum'
19
+ ? `${seed}${ETH_DERIVE_DEFAULT}`
20
+ : seed;
25
21
  }
26
22
  function isJsonPayload(value) {
27
- return value.genesisHash !== undefined;
23
+ return value.genesisHash !== undefined;
28
24
  }
29
25
  class Extension {
30
- #cachedUnlocks;
31
- #state;
32
- constructor(state) {
33
- this.#cachedUnlocks = {};
34
- this.#state = state;
35
- }
36
- transformAccounts(accounts) {
37
- return Object.values(accounts).map(_ref => {
38
- let {
39
- json: {
40
- address,
41
- meta
42
- },
43
- type
44
- } = _ref;
45
- return {
46
- address,
47
- isDefaultAuthSelected: this.#state.defaultAuthAccountSelection.includes(address),
48
- ...meta,
49
- type
50
- };
51
- });
52
- }
53
- accountsCreateExternal(_ref2) {
54
- let {
55
- address,
56
- genesisHash,
57
- name
58
- } = _ref2;
59
- _uiKeyring.default.addExternal(address, {
60
- genesisHash,
61
- name
62
- });
63
- return true;
64
- }
65
- accountsCreateHardware(_ref3) {
66
- let {
67
- accountIndex,
68
- address,
69
- addressOffset,
70
- genesisHash,
71
- hardwareType,
72
- name
73
- } = _ref3;
74
- _uiKeyring.default.addHardware(address, hardwareType, {
75
- accountIndex,
76
- addressOffset,
77
- genesisHash,
78
- name
79
- });
80
- return true;
81
- }
82
- accountsCreateSuri(_ref4) {
83
- let {
84
- genesisHash,
85
- name,
86
- password,
87
- suri,
88
- type
89
- } = _ref4;
90
- _uiKeyring.default.addUri(getSuri(suri, type), password, {
91
- genesisHash,
92
- name
93
- }, type);
94
- return true;
95
- }
96
- accountsChangePassword(_ref5) {
97
- let {
98
- address,
99
- newPass,
100
- oldPass
101
- } = _ref5;
102
- const pair = _uiKeyring.default.getPair(address);
103
- (0, _util.assert)(pair, 'Unable to find pair');
104
- try {
105
- if (!pair.isLocked) {
106
- pair.lock();
107
- }
108
- pair.decodePkcs8(oldPass);
109
- } catch (error) {
110
- throw new Error('oldPass is invalid');
111
- }
112
- _uiKeyring.default.encryptAccount(pair, newPass);
113
- return true;
114
- }
115
- accountsEdit(_ref6) {
116
- let {
117
- address,
118
- name
119
- } = _ref6;
120
- const pair = _uiKeyring.default.getPair(address);
121
- (0, _util.assert)(pair, 'Unable to find pair');
122
- _uiKeyring.default.saveAccountMeta(pair, {
123
- ...pair.meta,
124
- name
125
- });
126
- return true;
127
- }
128
- accountsExport(_ref7) {
129
- let {
130
- address,
131
- password
132
- } = _ref7;
133
- return {
134
- exportedJson: _uiKeyring.default.backupAccount(_uiKeyring.default.getPair(address), password)
135
- };
136
- }
137
- async accountsBatchExport(_ref8) {
138
- let {
139
- addresses,
140
- password
141
- } = _ref8;
142
- return {
143
- exportedJson: await _uiKeyring.default.backupAccounts(addresses, password)
144
- };
145
- }
146
- accountsForget(_ref9) {
147
- let {
148
- address
149
- } = _ref9;
150
- const authorizedAccountsDiff = [];
151
-
152
- // cycle through authUrls and prepare the array of diff
153
- Object.entries(this.#state.authUrls).forEach(_ref10 => {
154
- let [url, urlInfo] = _ref10;
155
- if (!urlInfo.authorizedAccounts.includes(address)) {
156
- return;
157
- }
158
- authorizedAccountsDiff.push([url, urlInfo.authorizedAccounts.filter(previousAddress => previousAddress !== address)]);
159
- });
160
- this.#state.updateAuthorizedAccounts(authorizedAccountsDiff);
161
-
162
- // cycle through default account selection for auth and remove any occurence of the account
163
- const newDefaultAuthAccounts = this.#state.defaultAuthAccountSelection.filter(defaultSelectionAddress => defaultSelectionAddress !== address);
164
- this.#state.updateDefaultAuthAccounts(newDefaultAuthAccounts);
165
- _uiKeyring.default.forgetAccount(address);
166
- return true;
167
- }
168
- refreshAccountPasswordCache(pair) {
169
- const {
170
- address
171
- } = pair;
172
- const savedExpiry = this.#cachedUnlocks[address] || 0;
173
- const remainingTime = savedExpiry - Date.now();
174
- if (remainingTime < 0) {
175
- this.#cachedUnlocks[address] = 0;
176
- pair.lock();
177
- return 0;
178
- }
179
- return remainingTime;
180
- }
181
- accountsShow(_ref11) {
182
- let {
183
- address,
184
- isShowing
185
- } = _ref11;
186
- const pair = _uiKeyring.default.getPair(address);
187
- (0, _util.assert)(pair, 'Unable to find pair');
188
- _uiKeyring.default.saveAccountMeta(pair, {
189
- ...pair.meta,
190
- isHidden: !isShowing
191
- });
192
- return true;
193
- }
194
- accountsTie(_ref12) {
195
- let {
196
- address,
197
- genesisHash
198
- } = _ref12;
199
- const pair = _uiKeyring.default.getPair(address);
200
- (0, _util.assert)(pair, 'Unable to find pair');
201
- _uiKeyring.default.saveAccountMeta(pair, {
202
- ...pair.meta,
203
- genesisHash
204
- });
205
- return true;
206
- }
207
- accountsValidate(_ref13) {
208
- let {
209
- address,
210
- password
211
- } = _ref13;
212
- try {
213
- _uiKeyring.default.backupAccount(_uiKeyring.default.getPair(address), password);
214
- return true;
215
- } catch (e) {
216
- return false;
217
- }
218
- }
219
- accountsSubscribe(id, port) {
220
- const cb = (0, _subscriptions.createSubscription)(id, port);
221
- const subscription = _accounts.accounts.subject.subscribe(accounts => cb(this.transformAccounts(accounts)));
222
- port.onDisconnect.addListener(() => {
223
- (0, _subscriptions.unsubscribe)(id);
224
- subscription.unsubscribe();
225
- });
226
- return true;
227
- }
228
- authorizeApprove(_ref14) {
229
- let {
230
- authorizedAccounts,
231
- id
232
- } = _ref14;
233
- const queued = this.#state.getAuthRequest(id);
234
- (0, _util.assert)(queued, 'Unable to find request');
235
- const {
236
- resolve
237
- } = queued;
238
- resolve({
239
- authorizedAccounts,
240
- result: true
241
- });
242
- return true;
243
- }
244
- authorizeUpdate(_ref15) {
245
- let {
246
- authorizedAccounts,
247
- url
248
- } = _ref15;
249
- return this.#state.updateAuthorizedAccounts([[url, authorizedAccounts]]);
250
- }
251
- getAuthList() {
252
- return {
253
- list: this.#state.authUrls
254
- };
255
- }
256
-
257
- // FIXME This looks very much like what we have in accounts
258
- authorizeSubscribe(id, port) {
259
- const cb = (0, _subscriptions.createSubscription)(id, port);
260
- const subscription = this.#state.authSubject.subscribe(requests => cb(requests));
261
- port.onDisconnect.addListener(() => {
262
- (0, _subscriptions.unsubscribe)(id);
263
- subscription.unsubscribe();
264
- });
265
- return true;
266
- }
267
- metadataApprove(_ref16) {
268
- let {
269
- id
270
- } = _ref16;
271
- const queued = this.#state.getMetaRequest(id);
272
- (0, _util.assert)(queued, 'Unable to find request');
273
- const {
274
- request,
275
- resolve
276
- } = queued;
277
- this.#state.saveMetadata(request);
278
- resolve(true);
279
- return true;
280
- }
281
- metadataGet(genesisHash) {
282
- return this.#state.knownMetadata.find(result => result.genesisHash === genesisHash) || null;
283
- }
284
- metadataList() {
285
- return this.#state.knownMetadata;
286
- }
287
- metadataReject(_ref17) {
288
- let {
289
- id
290
- } = _ref17;
291
- const queued = this.#state.getMetaRequest(id);
292
- (0, _util.assert)(queued, 'Unable to find request');
293
- const {
294
- reject
295
- } = queued;
296
- reject(new Error('Rejected'));
297
- return true;
298
- }
299
- metadataSubscribe(id, port) {
300
- const cb = (0, _subscriptions.createSubscription)(id, port);
301
- const subscription = this.#state.metaSubject.subscribe(requests => cb(requests));
302
- port.onDisconnect.addListener(() => {
303
- (0, _subscriptions.unsubscribe)(id);
304
- subscription.unsubscribe();
305
- });
306
- return true;
307
- }
308
- jsonRestore(_ref18) {
309
- let {
310
- file,
311
- password
312
- } = _ref18;
313
- try {
314
- _uiKeyring.default.restoreAccount(file, password);
315
- } catch (error) {
316
- throw new Error(error.message);
317
- }
318
- }
319
- batchRestore(_ref19) {
320
- let {
321
- file,
322
- password
323
- } = _ref19;
324
- try {
325
- _uiKeyring.default.restoreAccounts(file, password);
326
- } catch (error) {
327
- throw new Error(error.message);
328
- }
329
- }
330
- jsonGetAccountInfo(json) {
331
- try {
332
- const {
333
- address,
334
- meta: {
335
- genesisHash,
336
- name
337
- },
338
- type
339
- } = _uiKeyring.default.createFromJson(json);
340
- return {
341
- address,
342
- genesisHash,
343
- name,
344
- type
345
- };
346
- } catch (e) {
347
- console.error(e);
348
- throw new Error(e.message);
349
- }
350
- }
351
- seedCreate(_ref20) {
352
- let {
353
- length = SEED_DEFAULT_LENGTH,
354
- seed: _seed,
355
- type
356
- } = _ref20;
357
- const seed = _seed || (0, _utilCrypto.mnemonicGenerate)(length);
358
- return {
359
- address: _uiKeyring.default.createFromUri(getSuri(seed, type), {}, type).address,
360
- seed
361
- };
362
- }
363
- seedValidate(_ref21) {
364
- let {
365
- suri,
366
- type
367
- } = _ref21;
368
- const {
369
- phrase
370
- } = (0, _utilCrypto.keyExtractSuri)(suri);
371
- if ((0, _util.isHex)(phrase)) {
372
- (0, _util.assert)((0, _util.isHex)(phrase, 256), 'Hex seed needs to be 256-bits');
373
- } else {
374
- // sadly isHex detects as string, so we need a cast here
375
- (0, _util.assert)(SEED_LENGTHS.includes(phrase.split(' ').length), `Mnemonic needs to contain ${SEED_LENGTHS.join(', ')} words`);
376
- (0, _util.assert)((0, _utilCrypto.mnemonicValidate)(phrase), 'Not a valid mnemonic seed');
377
- }
378
- return {
379
- address: _uiKeyring.default.createFromUri(getSuri(suri, type), {}, type).address,
380
- suri
381
- };
382
- }
383
- signingApprovePassword(_ref22) {
384
- let {
385
- id,
386
- password,
387
- savePass
388
- } = _ref22;
389
- const queued = this.#state.getSignRequest(id);
390
- (0, _util.assert)(queued, 'Unable to find request');
391
- const {
392
- reject,
393
- request,
394
- resolve
395
- } = queued;
396
- const pair = _uiKeyring.default.getPair(queued.account.address);
397
- if (!pair) {
398
- reject(new Error('Unable to find pair'));
399
- return false;
400
- }
401
- this.refreshAccountPasswordCache(pair);
402
-
403
- // if the keyring pair is locked, the password is needed
404
- if (pair.isLocked && !password) {
405
- reject(new Error('Password needed to unlock the account'));
406
- }
407
- if (pair.isLocked) {
408
- pair.decodePkcs8(password);
409
- }
410
-
411
- // construct a new registry (avoiding pollution), between requests
412
- let registry;
413
- const {
414
- payload
415
- } = request;
416
- if (isJsonPayload(payload)) {
417
- // Get the metadata for the genesisHash
418
- const metadata = this.#state.knownMetadata.find(_ref23 => {
419
- let {
420
- genesisHash
421
- } = _ref23;
422
- return genesisHash === payload.genesisHash;
423
- });
424
- if (metadata) {
425
- // we have metadata, expand it and extract the info/registry
426
- const expanded = (0, _extensionChains.metadataExpand)(metadata, false);
427
- registry = expanded.registry;
428
- registry.setSignedExtensions(payload.signedExtensions, expanded.definition.userExtensions);
429
- } else {
430
- // we have no metadata, create a new registry
431
- registry = new _types.TypeRegistry();
432
- registry.setSignedExtensions(payload.signedExtensions);
433
- }
434
- } else {
435
- // for non-payload, just create a registry to use
436
- registry = new _types.TypeRegistry();
437
- }
438
- const result = request.sign(registry, pair);
439
- if (savePass) {
440
- // unlike queued.account.address the following
441
- // address is encoded with the default prefix
442
- // which what is used for password caching mapping
443
- this.#cachedUnlocks[pair.address] = Date.now() + _defaults.PASSWORD_EXPIRY_MS;
444
- } else {
445
- pair.lock();
446
- }
447
- resolve({
448
- id,
449
- ...result
450
- });
451
- return true;
452
- }
453
- signingApproveSignature(_ref24) {
454
- let {
455
- id,
456
- signature
457
- } = _ref24;
458
- const queued = this.#state.getSignRequest(id);
459
- (0, _util.assert)(queued, 'Unable to find request');
460
- const {
461
- resolve
462
- } = queued;
463
- resolve({
464
- id,
465
- signature
466
- });
467
- return true;
468
- }
469
- signingCancel(_ref25) {
470
- let {
471
- id
472
- } = _ref25;
473
- const queued = this.#state.getSignRequest(id);
474
- (0, _util.assert)(queued, 'Unable to find request');
475
- const {
476
- reject
477
- } = queued;
478
- reject(new Error('Cancelled'));
479
- return true;
480
- }
481
- signingIsLocked(_ref26) {
482
- let {
483
- id
484
- } = _ref26;
485
- const queued = this.#state.getSignRequest(id);
486
- (0, _util.assert)(queued, 'Unable to find request');
487
- const address = queued.request.payload.address;
488
- const pair = _uiKeyring.default.getPair(address);
489
- (0, _util.assert)(pair, 'Unable to find pair');
490
- const remainingTime = this.refreshAccountPasswordCache(pair);
491
- return {
492
- isLocked: pair.isLocked,
493
- remainingTime
494
- };
495
- }
496
-
497
- // FIXME This looks very much like what we have in authorization
498
- signingSubscribe(id, port) {
499
- const cb = (0, _subscriptions.createSubscription)(id, port);
500
- const subscription = this.#state.signSubject.subscribe(requests => cb(requests));
501
- port.onDisconnect.addListener(() => {
502
- (0, _subscriptions.unsubscribe)(id);
503
- subscription.unsubscribe();
504
- });
505
- return true;
506
- }
507
- windowOpen(path) {
508
- const url = `${chrome.extension.getURL('index.html')}#${path}`;
509
- if (!_defaults.ALLOWED_PATH.includes(path)) {
510
- console.error('Not allowed to open the url:', url);
511
- return false;
512
- }
513
- (0, _helpers.withErrorLog)(() => chrome.tabs.create({
514
- url
515
- }));
516
- return true;
517
- }
518
- derive(parentAddress, suri, password, metadata) {
519
- const parentPair = _uiKeyring.default.getPair(parentAddress);
520
- try {
521
- parentPair.decodePkcs8(password);
522
- } catch (e) {
523
- throw new Error('invalid password');
524
- }
525
- try {
526
- return parentPair.derive(suri, metadata);
527
- } catch (err) {
528
- throw new Error(`"${suri}" is not a valid derivation path`);
529
- }
530
- }
531
- derivationValidate(_ref27) {
532
- let {
533
- parentAddress,
534
- parentPassword,
535
- suri
536
- } = _ref27;
537
- const childPair = this.derive(parentAddress, suri, parentPassword, {});
538
- return {
539
- address: childPair.address,
540
- suri
541
- };
542
- }
543
- derivationCreate(_ref28) {
544
- let {
545
- genesisHash,
546
- name,
547
- parentAddress,
548
- parentPassword,
549
- password,
550
- suri
551
- } = _ref28;
552
- const childPair = this.derive(parentAddress, suri, parentPassword, {
553
- genesisHash,
554
- name,
555
- parentAddress,
556
- suri
557
- });
558
- _uiKeyring.default.addPair(childPair, password);
559
- return true;
560
- }
561
- removeAuthorization(url) {
562
- return {
563
- list: this.#state.removeAuthorization(url)
564
- };
565
- }
566
- deleteAuthRequest(requestId) {
567
- return this.#state.deleteAuthRequest(requestId);
568
- }
569
- updateCurrentTabs(_ref29) {
570
- let {
571
- urls
572
- } = _ref29;
573
- this.#state.udateCurrentTabsUrl(urls);
574
- }
575
- getConnectedTabsUrl() {
576
- return this.#state.getConnectedTabsUrl();
577
- }
578
-
579
- // Weird thought, the eslint override is not needed in Tabs
580
- // eslint-disable-next-line @typescript-eslint/require-await
581
- async handle(id, type, request, port) {
582
- switch (type) {
583
- case 'pri(authorize.approve)':
584
- return this.authorizeApprove(request);
585
- case 'pri(authorize.list)':
586
- return this.getAuthList();
587
- case 'pri(authorize.remove)':
588
- return this.removeAuthorization(request);
589
- case 'pri(authorize.delete.request)':
590
- return this.deleteAuthRequest(request);
591
- case 'pri(authorize.requests)':
592
- return port && this.authorizeSubscribe(id, port);
593
- case 'pri(authorize.update)':
594
- return this.authorizeUpdate(request);
595
- case 'pri(accounts.create.external)':
596
- return this.accountsCreateExternal(request);
597
- case 'pri(accounts.create.hardware)':
598
- return this.accountsCreateHardware(request);
599
- case 'pri(accounts.create.suri)':
600
- return this.accountsCreateSuri(request);
601
- case 'pri(accounts.changePassword)':
602
- return this.accountsChangePassword(request);
603
- case 'pri(accounts.edit)':
604
- return this.accountsEdit(request);
605
- case 'pri(accounts.export)':
606
- return this.accountsExport(request);
607
- case 'pri(accounts.batchExport)':
608
- return this.accountsBatchExport(request);
609
- case 'pri(accounts.forget)':
610
- return this.accountsForget(request);
611
- case 'pri(accounts.show)':
612
- return this.accountsShow(request);
613
- case 'pri(accounts.subscribe)':
614
- return port && this.accountsSubscribe(id, port);
615
- case 'pri(accounts.tie)':
616
- return this.accountsTie(request);
617
- case 'pri(accounts.validate)':
618
- return this.accountsValidate(request);
619
- case 'pri(metadata.approve)':
620
- return this.metadataApprove(request);
621
- case 'pri(metadata.get)':
622
- return this.metadataGet(request);
623
- case 'pri(metadata.list)':
624
- return this.metadataList();
625
- case 'pri(metadata.reject)':
626
- return this.metadataReject(request);
627
- case 'pri(metadata.requests)':
628
- return port && this.metadataSubscribe(id, port);
629
- case 'pri(activeTabsUrl.update)':
630
- return this.updateCurrentTabs(request);
631
- case 'pri(connectedTabsUrl.get)':
632
- return this.getConnectedTabsUrl();
633
- case 'pri(derivation.create)':
634
- return this.derivationCreate(request);
635
- case 'pri(derivation.validate)':
636
- return this.derivationValidate(request);
637
- case 'pri(json.restore)':
638
- return this.jsonRestore(request);
639
- case 'pri(json.batchRestore)':
640
- return this.batchRestore(request);
641
- case 'pri(json.account.info)':
642
- return this.jsonGetAccountInfo(request);
643
- case 'pri(ping)':
644
- return Promise.resolve(true);
645
- case 'pri(seed.create)':
646
- return this.seedCreate(request);
647
- case 'pri(seed.validate)':
648
- return this.seedValidate(request);
649
- case 'pri(settings.notification)':
650
- return this.#state.setNotification(request);
651
- case 'pri(signing.approve.password)':
652
- return this.signingApprovePassword(request);
653
- case 'pri(signing.approve.signature)':
654
- return this.signingApproveSignature(request);
655
- case 'pri(signing.cancel)':
656
- return this.signingCancel(request);
657
- case 'pri(signing.isLocked)':
658
- return this.signingIsLocked(request);
659
- case 'pri(signing.requests)':
660
- return port && this.signingSubscribe(id, port);
661
- case 'pri(window.open)':
662
- return this.windowOpen(request);
663
- default:
664
- throw new Error(`Unable to handle message of type ${type}`);
665
- }
666
- }
26
+ constructor(state) {
27
+ _Extension_cachedUnlocks.set(this, void 0);
28
+ _Extension_state.set(this, void 0);
29
+ tslib_1.__classPrivateFieldSet(this, _Extension_cachedUnlocks, {}, "f");
30
+ tslib_1.__classPrivateFieldSet(this, _Extension_state, state, "f");
31
+ }
32
+ transformAccounts(accounts) {
33
+ return Object.values(accounts).map(({ json: { address, meta }, type }) => ({
34
+ address,
35
+ isDefaultAuthSelected: tslib_1.__classPrivateFieldGet(this, _Extension_state, "f").defaultAuthAccountSelection.includes(address),
36
+ ...meta,
37
+ type
38
+ }));
39
+ }
40
+ accountsCreateExternal({ address, genesisHash, name }) {
41
+ ui_keyring_1.default.addExternal(address, { genesisHash, name });
42
+ return true;
43
+ }
44
+ accountsCreateHardware({ accountIndex, address, addressOffset, genesisHash, hardwareType, name }) {
45
+ ui_keyring_1.default.addHardware(address, hardwareType, { accountIndex, addressOffset, genesisHash, name });
46
+ return true;
47
+ }
48
+ accountsCreateSuri({ genesisHash, name, password, suri, type }) {
49
+ ui_keyring_1.default.addUri(getSuri(suri, type), password, { genesisHash, name }, type);
50
+ return true;
51
+ }
52
+ accountsChangePassword({ address, newPass, oldPass }) {
53
+ const pair = ui_keyring_1.default.getPair(address);
54
+ (0, util_1.assert)(pair, 'Unable to find pair');
55
+ try {
56
+ if (!pair.isLocked) {
57
+ pair.lock();
58
+ }
59
+ pair.decodePkcs8(oldPass);
60
+ }
61
+ catch (error) {
62
+ throw new Error('oldPass is invalid');
63
+ }
64
+ ui_keyring_1.default.encryptAccount(pair, newPass);
65
+ return true;
66
+ }
67
+ accountsEdit({ address, name }) {
68
+ const pair = ui_keyring_1.default.getPair(address);
69
+ (0, util_1.assert)(pair, 'Unable to find pair');
70
+ ui_keyring_1.default.saveAccountMeta(pair, { ...pair.meta, name });
71
+ return true;
72
+ }
73
+ accountsExport({ address, password }) {
74
+ return { exportedJson: ui_keyring_1.default.backupAccount(ui_keyring_1.default.getPair(address), password) };
75
+ }
76
+ async accountsBatchExport({ addresses, password }) {
77
+ return {
78
+ exportedJson: await ui_keyring_1.default.backupAccounts(addresses, password)
79
+ };
80
+ }
81
+ accountsForget({ address }) {
82
+ const authorizedAccountsDiff = [];
83
+ // cycle through authUrls and prepare the array of diff
84
+ Object.entries(tslib_1.__classPrivateFieldGet(this, _Extension_state, "f").authUrls).forEach(([url, urlInfo]) => {
85
+ if (!urlInfo.authorizedAccounts.includes(address)) {
86
+ return;
87
+ }
88
+ authorizedAccountsDiff.push([url, urlInfo.authorizedAccounts.filter((previousAddress) => previousAddress !== address)]);
89
+ });
90
+ tslib_1.__classPrivateFieldGet(this, _Extension_state, "f").updateAuthorizedAccounts(authorizedAccountsDiff);
91
+ // cycle through default account selection for auth and remove any occurence of the account
92
+ const newDefaultAuthAccounts = tslib_1.__classPrivateFieldGet(this, _Extension_state, "f").defaultAuthAccountSelection.filter((defaultSelectionAddress) => defaultSelectionAddress !== address);
93
+ tslib_1.__classPrivateFieldGet(this, _Extension_state, "f").updateDefaultAuthAccounts(newDefaultAuthAccounts);
94
+ ui_keyring_1.default.forgetAccount(address);
95
+ return true;
96
+ }
97
+ refreshAccountPasswordCache(pair) {
98
+ const { address } = pair;
99
+ const savedExpiry = tslib_1.__classPrivateFieldGet(this, _Extension_cachedUnlocks, "f")[address] || 0;
100
+ const remainingTime = savedExpiry - Date.now();
101
+ if (remainingTime < 0) {
102
+ tslib_1.__classPrivateFieldGet(this, _Extension_cachedUnlocks, "f")[address] = 0;
103
+ pair.lock();
104
+ return 0;
105
+ }
106
+ return remainingTime;
107
+ }
108
+ accountsShow({ address, isShowing }) {
109
+ const pair = ui_keyring_1.default.getPair(address);
110
+ (0, util_1.assert)(pair, 'Unable to find pair');
111
+ ui_keyring_1.default.saveAccountMeta(pair, { ...pair.meta, isHidden: !isShowing });
112
+ return true;
113
+ }
114
+ accountsTie({ address, genesisHash }) {
115
+ const pair = ui_keyring_1.default.getPair(address);
116
+ (0, util_1.assert)(pair, 'Unable to find pair');
117
+ ui_keyring_1.default.saveAccountMeta(pair, { ...pair.meta, genesisHash });
118
+ return true;
119
+ }
120
+ accountsValidate({ address, password }) {
121
+ try {
122
+ ui_keyring_1.default.backupAccount(ui_keyring_1.default.getPair(address), password);
123
+ return true;
124
+ }
125
+ catch (e) {
126
+ return false;
127
+ }
128
+ }
129
+ accountsSubscribe(id, port) {
130
+ const cb = (0, subscriptions_1.createSubscription)(id, port);
131
+ const subscription = accounts_1.accounts.subject.subscribe((accounts) => cb(this.transformAccounts(accounts)));
132
+ port.onDisconnect.addListener(() => {
133
+ (0, subscriptions_1.unsubscribe)(id);
134
+ subscription.unsubscribe();
135
+ });
136
+ return true;
137
+ }
138
+ authorizeApprove({ authorizedAccounts, id }) {
139
+ const queued = tslib_1.__classPrivateFieldGet(this, _Extension_state, "f").getAuthRequest(id);
140
+ (0, util_1.assert)(queued, 'Unable to find request');
141
+ const { resolve } = queued;
142
+ resolve({ authorizedAccounts, result: true });
143
+ return true;
144
+ }
145
+ authorizeUpdate({ authorizedAccounts, url }) {
146
+ return tslib_1.__classPrivateFieldGet(this, _Extension_state, "f").updateAuthorizedAccounts([[url, authorizedAccounts]]);
147
+ }
148
+ getAuthList() {
149
+ return { list: tslib_1.__classPrivateFieldGet(this, _Extension_state, "f").authUrls };
150
+ }
151
+ // FIXME This looks very much like what we have in accounts
152
+ authorizeSubscribe(id, port) {
153
+ const cb = (0, subscriptions_1.createSubscription)(id, port);
154
+ const subscription = tslib_1.__classPrivateFieldGet(this, _Extension_state, "f").authSubject.subscribe((requests) => cb(requests));
155
+ port.onDisconnect.addListener(() => {
156
+ (0, subscriptions_1.unsubscribe)(id);
157
+ subscription.unsubscribe();
158
+ });
159
+ return true;
160
+ }
161
+ metadataApprove({ id }) {
162
+ const queued = tslib_1.__classPrivateFieldGet(this, _Extension_state, "f").getMetaRequest(id);
163
+ (0, util_1.assert)(queued, 'Unable to find request');
164
+ const { request, resolve } = queued;
165
+ tslib_1.__classPrivateFieldGet(this, _Extension_state, "f").saveMetadata(request);
166
+ resolve(true);
167
+ return true;
168
+ }
169
+ metadataGet(genesisHash) {
170
+ return tslib_1.__classPrivateFieldGet(this, _Extension_state, "f").knownMetadata.find((result) => result.genesisHash === genesisHash) || null;
171
+ }
172
+ metadataList() {
173
+ return tslib_1.__classPrivateFieldGet(this, _Extension_state, "f").knownMetadata;
174
+ }
175
+ metadataReject({ id }) {
176
+ const queued = tslib_1.__classPrivateFieldGet(this, _Extension_state, "f").getMetaRequest(id);
177
+ (0, util_1.assert)(queued, 'Unable to find request');
178
+ const { reject } = queued;
179
+ reject(new Error('Rejected'));
180
+ return true;
181
+ }
182
+ metadataSubscribe(id, port) {
183
+ const cb = (0, subscriptions_1.createSubscription)(id, port);
184
+ const subscription = tslib_1.__classPrivateFieldGet(this, _Extension_state, "f").metaSubject.subscribe((requests) => cb(requests));
185
+ port.onDisconnect.addListener(() => {
186
+ (0, subscriptions_1.unsubscribe)(id);
187
+ subscription.unsubscribe();
188
+ });
189
+ return true;
190
+ }
191
+ jsonRestore({ file, password }) {
192
+ try {
193
+ ui_keyring_1.default.restoreAccount(file, password);
194
+ }
195
+ catch (error) {
196
+ throw new Error(error.message);
197
+ }
198
+ }
199
+ batchRestore({ file, password }) {
200
+ try {
201
+ ui_keyring_1.default.restoreAccounts(file, password);
202
+ }
203
+ catch (error) {
204
+ throw new Error(error.message);
205
+ }
206
+ }
207
+ jsonGetAccountInfo(json) {
208
+ try {
209
+ const { address, meta: { genesisHash, name }, type } = ui_keyring_1.default.createFromJson(json);
210
+ return {
211
+ address,
212
+ genesisHash,
213
+ name,
214
+ type
215
+ };
216
+ }
217
+ catch (e) {
218
+ console.error(e);
219
+ throw new Error(e.message);
220
+ }
221
+ }
222
+ seedCreate({ length = SEED_DEFAULT_LENGTH, seed: _seed, type }) {
223
+ const seed = _seed || (0, util_crypto_1.mnemonicGenerate)(length);
224
+ return {
225
+ address: ui_keyring_1.default.createFromUri(getSuri(seed, type), {}, type).address,
226
+ seed
227
+ };
228
+ }
229
+ seedValidate({ suri, type }) {
230
+ const { phrase } = (0, util_crypto_1.keyExtractSuri)(suri);
231
+ if ((0, util_1.isHex)(phrase)) {
232
+ (0, util_1.assert)((0, util_1.isHex)(phrase, 256), 'Hex seed needs to be 256-bits');
233
+ }
234
+ else {
235
+ // sadly isHex detects as string, so we need a cast here
236
+ (0, util_1.assert)(SEED_LENGTHS.includes((phrase).split(' ').length), `Mnemonic needs to contain ${SEED_LENGTHS.join(', ')} words`);
237
+ (0, util_1.assert)((0, util_crypto_1.mnemonicValidate)(phrase), 'Not a valid mnemonic seed');
238
+ }
239
+ return {
240
+ address: ui_keyring_1.default.createFromUri(getSuri(suri, type), {}, type).address,
241
+ suri
242
+ };
243
+ }
244
+ signingApprovePassword({ id, password, savePass }) {
245
+ const queued = tslib_1.__classPrivateFieldGet(this, _Extension_state, "f").getSignRequest(id);
246
+ (0, util_1.assert)(queued, 'Unable to find request');
247
+ const { reject, request, resolve } = queued;
248
+ const pair = ui_keyring_1.default.getPair(queued.account.address);
249
+ if (!pair) {
250
+ reject(new Error('Unable to find pair'));
251
+ return false;
252
+ }
253
+ this.refreshAccountPasswordCache(pair);
254
+ // if the keyring pair is locked, the password is needed
255
+ if (pair.isLocked && !password) {
256
+ reject(new Error('Password needed to unlock the account'));
257
+ }
258
+ if (pair.isLocked) {
259
+ pair.decodePkcs8(password);
260
+ }
261
+ // construct a new registry (avoiding pollution), between requests
262
+ let registry;
263
+ const { payload } = request;
264
+ if (isJsonPayload(payload)) {
265
+ // Get the metadata for the genesisHash
266
+ const metadata = tslib_1.__classPrivateFieldGet(this, _Extension_state, "f").knownMetadata.find(({ genesisHash }) => genesisHash === payload.genesisHash);
267
+ if (metadata) {
268
+ // we have metadata, expand it and extract the info/registry
269
+ const expanded = (0, extension_chains_1.metadataExpand)(metadata, false);
270
+ registry = expanded.registry;
271
+ registry.setSignedExtensions(payload.signedExtensions, expanded.definition.userExtensions);
272
+ }
273
+ else {
274
+ // we have no metadata, create a new registry
275
+ registry = new types_1.TypeRegistry();
276
+ registry.setSignedExtensions(payload.signedExtensions);
277
+ }
278
+ }
279
+ else {
280
+ // for non-payload, just create a registry to use
281
+ registry = new types_1.TypeRegistry();
282
+ }
283
+ const result = request.sign(registry, pair);
284
+ if (savePass) {
285
+ // unlike queued.account.address the following
286
+ // address is encoded with the default prefix
287
+ // which what is used for password caching mapping
288
+ tslib_1.__classPrivateFieldGet(this, _Extension_cachedUnlocks, "f")[pair.address] = Date.now() + defaults_1.PASSWORD_EXPIRY_MS;
289
+ }
290
+ else {
291
+ pair.lock();
292
+ }
293
+ resolve({
294
+ id,
295
+ ...result
296
+ });
297
+ return true;
298
+ }
299
+ signingApproveSignature({ id, signature }) {
300
+ const queued = tslib_1.__classPrivateFieldGet(this, _Extension_state, "f").getSignRequest(id);
301
+ (0, util_1.assert)(queued, 'Unable to find request');
302
+ const { resolve } = queued;
303
+ resolve({ id, signature });
304
+ return true;
305
+ }
306
+ signingCancel({ id }) {
307
+ const queued = tslib_1.__classPrivateFieldGet(this, _Extension_state, "f").getSignRequest(id);
308
+ (0, util_1.assert)(queued, 'Unable to find request');
309
+ const { reject } = queued;
310
+ reject(new Error('Cancelled'));
311
+ return true;
312
+ }
313
+ signingIsLocked({ id }) {
314
+ const queued = tslib_1.__classPrivateFieldGet(this, _Extension_state, "f").getSignRequest(id);
315
+ (0, util_1.assert)(queued, 'Unable to find request');
316
+ const address = queued.request.payload.address;
317
+ const pair = ui_keyring_1.default.getPair(address);
318
+ (0, util_1.assert)(pair, 'Unable to find pair');
319
+ const remainingTime = this.refreshAccountPasswordCache(pair);
320
+ return {
321
+ isLocked: pair.isLocked,
322
+ remainingTime
323
+ };
324
+ }
325
+ // FIXME This looks very much like what we have in authorization
326
+ signingSubscribe(id, port) {
327
+ const cb = (0, subscriptions_1.createSubscription)(id, port);
328
+ const subscription = tslib_1.__classPrivateFieldGet(this, _Extension_state, "f").signSubject.subscribe((requests) => cb(requests));
329
+ port.onDisconnect.addListener(() => {
330
+ (0, subscriptions_1.unsubscribe)(id);
331
+ subscription.unsubscribe();
332
+ });
333
+ return true;
334
+ }
335
+ windowOpen(path) {
336
+ const url = `${chrome.extension.getURL('index.html')}#${path}`;
337
+ if (!defaults_1.ALLOWED_PATH.includes(path)) {
338
+ console.error('Not allowed to open the url:', url);
339
+ return false;
340
+ }
341
+ (0, helpers_1.withErrorLog)(() => chrome.tabs.create({ url }));
342
+ return true;
343
+ }
344
+ derive(parentAddress, suri, password, metadata) {
345
+ const parentPair = ui_keyring_1.default.getPair(parentAddress);
346
+ try {
347
+ parentPair.decodePkcs8(password);
348
+ }
349
+ catch (e) {
350
+ throw new Error('invalid password');
351
+ }
352
+ try {
353
+ return parentPair.derive(suri, metadata);
354
+ }
355
+ catch (err) {
356
+ throw new Error(`"${suri}" is not a valid derivation path`);
357
+ }
358
+ }
359
+ derivationValidate({ parentAddress, parentPassword, suri }) {
360
+ const childPair = this.derive(parentAddress, suri, parentPassword, {});
361
+ return {
362
+ address: childPair.address,
363
+ suri
364
+ };
365
+ }
366
+ derivationCreate({ genesisHash, name, parentAddress, parentPassword, password, suri }) {
367
+ const childPair = this.derive(parentAddress, suri, parentPassword, {
368
+ genesisHash,
369
+ name,
370
+ parentAddress,
371
+ suri
372
+ });
373
+ ui_keyring_1.default.addPair(childPair, password);
374
+ return true;
375
+ }
376
+ removeAuthorization(url) {
377
+ return { list: tslib_1.__classPrivateFieldGet(this, _Extension_state, "f").removeAuthorization(url) };
378
+ }
379
+ deleteAuthRequest(requestId) {
380
+ return tslib_1.__classPrivateFieldGet(this, _Extension_state, "f").deleteAuthRequest(requestId);
381
+ }
382
+ updateCurrentTabs({ urls }) {
383
+ tslib_1.__classPrivateFieldGet(this, _Extension_state, "f").udateCurrentTabsUrl(urls);
384
+ }
385
+ getConnectedTabsUrl() {
386
+ return tslib_1.__classPrivateFieldGet(this, _Extension_state, "f").getConnectedTabsUrl();
387
+ }
388
+ // Weird thought, the eslint override is not needed in Tabs
389
+ // eslint-disable-next-line @typescript-eslint/require-await
390
+ async handle(id, type, request, port) {
391
+ switch (type) {
392
+ case 'pri(authorize.approve)':
393
+ return this.authorizeApprove(request);
394
+ case 'pri(authorize.list)':
395
+ return this.getAuthList();
396
+ case 'pri(authorize.remove)':
397
+ return this.removeAuthorization(request);
398
+ case 'pri(authorize.delete.request)':
399
+ return this.deleteAuthRequest(request);
400
+ case 'pri(authorize.requests)':
401
+ return port && this.authorizeSubscribe(id, port);
402
+ case 'pri(authorize.update)':
403
+ return this.authorizeUpdate(request);
404
+ case 'pri(accounts.create.external)':
405
+ return this.accountsCreateExternal(request);
406
+ case 'pri(accounts.create.hardware)':
407
+ return this.accountsCreateHardware(request);
408
+ case 'pri(accounts.create.suri)':
409
+ return this.accountsCreateSuri(request);
410
+ case 'pri(accounts.changePassword)':
411
+ return this.accountsChangePassword(request);
412
+ case 'pri(accounts.edit)':
413
+ return this.accountsEdit(request);
414
+ case 'pri(accounts.export)':
415
+ return this.accountsExport(request);
416
+ case 'pri(accounts.batchExport)':
417
+ return this.accountsBatchExport(request);
418
+ case 'pri(accounts.forget)':
419
+ return this.accountsForget(request);
420
+ case 'pri(accounts.show)':
421
+ return this.accountsShow(request);
422
+ case 'pri(accounts.subscribe)':
423
+ return port && this.accountsSubscribe(id, port);
424
+ case 'pri(accounts.tie)':
425
+ return this.accountsTie(request);
426
+ case 'pri(accounts.validate)':
427
+ return this.accountsValidate(request);
428
+ case 'pri(metadata.approve)':
429
+ return this.metadataApprove(request);
430
+ case 'pri(metadata.get)':
431
+ return this.metadataGet(request);
432
+ case 'pri(metadata.list)':
433
+ return this.metadataList();
434
+ case 'pri(metadata.reject)':
435
+ return this.metadataReject(request);
436
+ case 'pri(metadata.requests)':
437
+ return port && this.metadataSubscribe(id, port);
438
+ case 'pri(activeTabsUrl.update)':
439
+ return this.updateCurrentTabs(request);
440
+ case 'pri(connectedTabsUrl.get)':
441
+ return this.getConnectedTabsUrl();
442
+ case 'pri(derivation.create)':
443
+ return this.derivationCreate(request);
444
+ case 'pri(derivation.validate)':
445
+ return this.derivationValidate(request);
446
+ case 'pri(json.restore)':
447
+ return this.jsonRestore(request);
448
+ case 'pri(json.batchRestore)':
449
+ return this.batchRestore(request);
450
+ case 'pri(json.account.info)':
451
+ return this.jsonGetAccountInfo(request);
452
+ case 'pri(ping)':
453
+ return Promise.resolve(true);
454
+ case 'pri(seed.create)':
455
+ return this.seedCreate(request);
456
+ case 'pri(seed.validate)':
457
+ return this.seedValidate(request);
458
+ case 'pri(settings.notification)':
459
+ return tslib_1.__classPrivateFieldGet(this, _Extension_state, "f").setNotification(request);
460
+ case 'pri(signing.approve.password)':
461
+ return this.signingApprovePassword(request);
462
+ case 'pri(signing.approve.signature)':
463
+ return this.signingApproveSignature(request);
464
+ case 'pri(signing.cancel)':
465
+ return this.signingCancel(request);
466
+ case 'pri(signing.isLocked)':
467
+ return this.signingIsLocked(request);
468
+ case 'pri(signing.requests)':
469
+ return port && this.signingSubscribe(id, port);
470
+ case 'pri(window.open)':
471
+ return this.windowOpen(request);
472
+ default:
473
+ throw new Error(`Unable to handle message of type ${type}`);
474
+ }
475
+ }
667
476
  }
668
- exports.default = Extension;
477
+ exports.default = Extension;
478
+ _Extension_cachedUnlocks = new WeakMap(), _Extension_state = new WeakMap();