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