@polkadot/extension-base 0.59.2 → 0.61.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.
@@ -66,35 +66,38 @@ async function extractMetadata(store) {
66
66
  });
67
67
  }
68
68
  class State {
69
- __internal__authUrls = {};
70
- __internal__authRequests = {};
71
- __internal__metaStore = new index_js_1.MetadataStore();
69
+ #authUrls = new Map();
70
+ #lastRequestTimestamps = new Map();
71
+ #maxEntries = 10;
72
+ #rateLimitInterval = 3000; // 3 seconds
73
+ #authRequests = {};
74
+ #metaStore = new index_js_1.MetadataStore();
72
75
  // Map of providers currently injected in tabs
73
- __internal__injectedProviders = new Map();
74
- __internal__metaRequests = {};
75
- __internal__notification = ui_settings_1.settings.notification;
76
+ #injectedProviders = new Map();
77
+ #metaRequests = {};
78
+ #notification = ui_settings_1.settings.notification;
76
79
  // Map of all providers exposed by the extension, they are retrievable by key
77
- __internal__providers;
78
- __internal__signRequests = {};
79
- __internal__windows = [];
80
- __internal__connectedTabsUrl = [];
80
+ #providers;
81
+ #signRequests = {};
82
+ #windows = [];
83
+ #connectedTabsUrl = [];
81
84
  authSubject = new rxjs_1.BehaviorSubject([]);
82
85
  metaSubject = new rxjs_1.BehaviorSubject([]);
83
86
  signSubject = new rxjs_1.BehaviorSubject([]);
84
87
  authUrlSubjects = {};
85
88
  defaultAuthAccountSelection = [];
86
89
  constructor(providers = {}) {
87
- this.__internal__providers = providers;
90
+ this.#providers = providers;
88
91
  }
89
92
  async init() {
90
- await extractMetadata(this.__internal__metaStore);
93
+ await extractMetadata(this.#metaStore);
91
94
  // retrieve previously set authorizations
92
95
  const storageAuthUrls = await chrome.storage.local.get(AUTH_URLS_KEY);
93
96
  const authString = storageAuthUrls?.[AUTH_URLS_KEY] || '{}';
94
97
  const previousAuth = JSON.parse(authString);
95
- this.__internal__authUrls = previousAuth;
98
+ this.#authUrls = new Map(Object.entries(previousAuth));
96
99
  // Initialize authUrlSubjects for each URL
97
- Object.entries(previousAuth).forEach(([url, authInfo]) => {
100
+ this.#authUrls.forEach((authInfo, url) => {
98
101
  this.authUrlSubjects[url] = new rxjs_1.BehaviorSubject(authInfo);
99
102
  });
100
103
  // retrieve previously set default auth accounts
@@ -107,49 +110,49 @@ class State {
107
110
  return (0, extension_chains_1.knownMetadata)();
108
111
  }
109
112
  get numAuthRequests() {
110
- return Object.keys(this.__internal__authRequests).length;
113
+ return Object.keys(this.#authRequests).length;
111
114
  }
112
115
  get numMetaRequests() {
113
- return Object.keys(this.__internal__metaRequests).length;
116
+ return Object.keys(this.#metaRequests).length;
114
117
  }
115
118
  get numSignRequests() {
116
- return Object.keys(this.__internal__signRequests).length;
119
+ return Object.keys(this.#signRequests).length;
117
120
  }
118
121
  get allAuthRequests() {
119
122
  return Object
120
- .values(this.__internal__authRequests)
123
+ .values(this.#authRequests)
121
124
  .map(({ id, request, url }) => ({ id, request, url }));
122
125
  }
123
126
  get allMetaRequests() {
124
127
  return Object
125
- .values(this.__internal__metaRequests)
128
+ .values(this.#metaRequests)
126
129
  .map(({ id, request, url }) => ({ id, request, url }));
127
130
  }
128
131
  get allSignRequests() {
129
132
  return Object
130
- .values(this.__internal__signRequests)
133
+ .values(this.#signRequests)
131
134
  .map(({ account, id, request, url }) => ({ account, id, request, url }));
132
135
  }
133
136
  get authUrls() {
134
- return this.__internal__authUrls;
137
+ return Object.fromEntries(this.#authUrls);
135
138
  }
136
139
  popupClose() {
137
- this.__internal__windows.forEach((id) => (0, helpers_js_1.withErrorLog)(() => chrome.windows.remove(id)));
138
- this.__internal__windows = [];
140
+ this.#windows.forEach((id) => (0, helpers_js_1.withErrorLog)(() => chrome.windows.remove(id)));
141
+ this.#windows = [];
139
142
  }
140
143
  popupOpen() {
141
- this.__internal__notification !== 'extension' &&
142
- chrome.windows.create(this.__internal__notification === 'window'
144
+ this.#notification !== 'extension' &&
145
+ chrome.windows.create(this.#notification === 'window'
143
146
  ? NORMAL_WINDOW_OPTS
144
147
  : POPUP_WINDOW_OPTS, (window) => {
145
148
  if (window) {
146
- this.__internal__windows.push(window.id || 0);
149
+ this.#windows.push(window.id || 0);
147
150
  }
148
151
  });
149
152
  }
150
153
  authComplete = (id, resolve, reject) => {
151
154
  const complete = async (authorizedAccounts = []) => {
152
- const { idStr, request: { origin }, url } = this.__internal__authRequests[id];
155
+ const { idStr, request: { origin }, url } = this.#authRequests[id];
153
156
  const strippedUrl = this.stripUrl(url);
154
157
  const authInfo = {
155
158
  authorizedAccounts,
@@ -158,7 +161,7 @@ class State {
158
161
  origin,
159
162
  url
160
163
  };
161
- this.__internal__authUrls[strippedUrl] = authInfo;
164
+ this.#authUrls.set(strippedUrl, authInfo);
162
165
  if (!this.authUrlSubjects[strippedUrl]) {
163
166
  this.authUrlSubjects[strippedUrl] = new rxjs_1.BehaviorSubject(authInfo);
164
167
  }
@@ -167,14 +170,14 @@ class State {
167
170
  }
168
171
  await this.saveCurrentAuthList();
169
172
  await this.updateDefaultAuthAccounts(authorizedAccounts);
170
- delete this.__internal__authRequests[id];
173
+ delete this.#authRequests[id];
171
174
  this.updateIconAuth(true);
172
175
  };
173
176
  return {
174
177
  // eslint-disable-next-line @typescript-eslint/no-misused-promises
175
178
  reject: async (error) => {
176
179
  if (error.message === 'Cancelled') {
177
- delete this.__internal__authRequests[id];
180
+ delete this.#authRequests[id];
178
181
  this.updateIconAuth(true);
179
182
  reject(new Error('Connection request was cancelled by the user.'));
180
183
  }
@@ -212,17 +215,17 @@ class State {
212
215
  : undefined;
213
216
  })
214
217
  .filter((value) => !!value);
215
- this.__internal__connectedTabsUrl = connectedTabs;
218
+ this.#connectedTabsUrl = connectedTabs;
216
219
  }
217
220
  getConnectedTabsUrl() {
218
- return this.__internal__connectedTabsUrl;
221
+ return this.#connectedTabsUrl;
219
222
  }
220
223
  deleteAuthRequest(requestId) {
221
- delete this.__internal__authRequests[requestId];
224
+ delete this.#authRequests[requestId];
222
225
  this.updateIconAuth(true);
223
226
  }
224
227
  async saveCurrentAuthList() {
225
- await chrome.storage.local.set({ [AUTH_URLS_KEY]: JSON.stringify(this.__internal__authUrls) });
228
+ await chrome.storage.local.set({ [AUTH_URLS_KEY]: JSON.stringify(Object.fromEntries(this.#authUrls)) });
226
229
  }
227
230
  async saveDefaultAuthAccounts() {
228
231
  await chrome.storage.local.set({ [DEFAULT_AUTH_ACCOUNTS]: JSON.stringify(this.defaultAuthAccountSelection) });
@@ -233,7 +236,7 @@ class State {
233
236
  }
234
237
  metaComplete = (id, resolve, reject) => {
235
238
  const complete = () => {
236
- delete this.__internal__metaRequests[id];
239
+ delete this.#metaRequests[id];
237
240
  this.updateIconMeta(true);
238
241
  };
239
242
  return {
@@ -249,7 +252,7 @@ class State {
249
252
  };
250
253
  signComplete = (id, resolve, reject) => {
251
254
  const complete = () => {
252
- delete this.__internal__signRequests[id];
255
+ delete this.#signRequests[id];
253
256
  this.updateIconSign(true);
254
257
  };
255
258
  return {
@@ -264,9 +267,22 @@ class State {
264
267
  };
265
268
  };
266
269
  stripUrl(url) {
267
- (0, util_1.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:`);
268
- const parts = url.split('/');
269
- return parts[2];
270
+ try {
271
+ const parsedUrl = new URL(url);
272
+ if (!['http:', 'https:', 'ipfs:', 'ipns:'].includes(parsedUrl.protocol)) {
273
+ throw new Error(`Invalid protocol ${parsedUrl.protocol}`);
274
+ }
275
+ // For ipfs/ipns which don't have a standard origin, we handle it differently.
276
+ if (parsedUrl.protocol === 'ipfs:' || parsedUrl.protocol === 'ipns:') {
277
+ // ipfs://<hash> | ipns://<hash>
278
+ return `${parsedUrl.protocol}//${parsedUrl.hostname}`;
279
+ }
280
+ return parsedUrl.origin;
281
+ }
282
+ catch (e) {
283
+ console.error(e);
284
+ throw new Error('Invalid URL');
285
+ }
270
286
  }
271
287
  updateIcon(shouldClose) {
272
288
  const authCount = this.numAuthRequests;
@@ -283,15 +299,15 @@ class State {
283
299
  }
284
300
  }
285
301
  async removeAuthorization(url) {
286
- const entry = this.__internal__authUrls[url];
302
+ const entry = this.#authUrls.get(url);
287
303
  (0, util_1.assert)(entry, `The source ${url} is not known`);
288
- delete this.__internal__authUrls[url];
304
+ this.#authUrls.delete(url);
289
305
  await this.saveCurrentAuthList();
290
306
  if (this.authUrlSubjects[url]) {
291
307
  entry.authorizedAccounts = [];
292
308
  this.authUrlSubjects[url].next(entry);
293
309
  }
294
- return this.__internal__authUrls;
310
+ return this.authUrls;
295
311
  }
296
312
  updateIconAuth(shouldClose) {
297
313
  this.authSubject.next(this.allAuthRequests);
@@ -307,8 +323,12 @@ class State {
307
323
  }
308
324
  async updateAuthorizedAccounts(authorizedAccountsDiff) {
309
325
  authorizedAccountsDiff.forEach(([url, authorizedAccountDiff]) => {
310
- this.__internal__authUrls[url].authorizedAccounts = authorizedAccountDiff;
311
- this.authUrlSubjects[url].next(this.__internal__authUrls[url]);
326
+ const authInfo = this.#authUrls.get(url);
327
+ if (authInfo) {
328
+ authInfo.authorizedAccounts = authorizedAccountDiff;
329
+ this.#authUrls.set(url, authInfo);
330
+ this.authUrlSubjects[url].next(authInfo);
331
+ }
312
332
  });
313
333
  await this.saveCurrentAuthList();
314
334
  }
@@ -316,12 +336,13 @@ class State {
316
336
  const idStr = this.stripUrl(url);
317
337
  // Do not enqueue duplicate authorization requests.
318
338
  const isDuplicate = Object
319
- .values(this.__internal__authRequests)
339
+ .values(this.#authRequests)
320
340
  .some((request) => request.idStr === idStr);
321
341
  (0, util_1.assert)(!isDuplicate, `The source ${url} has a pending authorization request`);
322
- if (this.__internal__authUrls[idStr]) {
342
+ if (this.#authUrls.has(idStr)) {
323
343
  // this url was seen in the past
324
- (0, util_1.assert)(this.__internal__authUrls[idStr].authorizedAccounts || this.__internal__authUrls[idStr].isAllowed, `The source ${url} is not allowed to interact with this extension`);
344
+ const authInfo = this.#authUrls.get(idStr);
345
+ (0, util_1.assert)(authInfo?.authorizedAccounts || authInfo?.isAllowed, `The source ${url} is not allowed to interact with this extension`);
325
346
  return {
326
347
  authorizedAccounts: [],
327
348
  result: false
@@ -329,7 +350,7 @@ class State {
329
350
  }
330
351
  return new Promise((resolve, reject) => {
331
352
  const id = (0, getId_js_1.getId)();
332
- this.__internal__authRequests[id] = {
353
+ this.#authRequests[id] = {
333
354
  ...this.authComplete(id, resolve, reject),
334
355
  id,
335
356
  idStr,
@@ -341,14 +362,14 @@ class State {
341
362
  });
342
363
  }
343
364
  ensureUrlAuthorized(url) {
344
- const entry = this.__internal__authUrls[this.stripUrl(url)];
365
+ const entry = this.#authUrls.get(this.stripUrl(url));
345
366
  (0, util_1.assert)(entry, `The source ${url} has not been enabled yet`);
346
367
  return true;
347
368
  }
348
369
  injectMetadata(url, request) {
349
370
  return new Promise((resolve, reject) => {
350
371
  const id = (0, getId_js_1.getId)();
351
- this.__internal__metaRequests[id] = {
372
+ this.#metaRequests[id] = {
352
373
  ...this.metaComplete(id, resolve, reject),
353
374
  id,
354
375
  request,
@@ -359,73 +380,92 @@ class State {
359
380
  });
360
381
  }
361
382
  getAuthRequest(id) {
362
- return this.__internal__authRequests[id];
383
+ return this.#authRequests[id];
363
384
  }
364
385
  getMetaRequest(id) {
365
- return this.__internal__metaRequests[id];
386
+ return this.#metaRequests[id];
366
387
  }
367
388
  getSignRequest(id) {
368
- return this.__internal__signRequests[id];
389
+ return this.#signRequests[id];
369
390
  }
370
391
  // List all providers the extension is exposing
371
392
  rpcListProviders() {
372
- return Promise.resolve(Object.keys(this.__internal__providers).reduce((acc, key) => {
373
- acc[key] = this.__internal__providers[key].meta;
393
+ return Promise.resolve(Object.keys(this.#providers).reduce((acc, key) => {
394
+ acc[key] = this.#providers[key].meta;
374
395
  return acc;
375
396
  }, {}));
376
397
  }
377
398
  rpcSend(request, port) {
378
- const provider = this.__internal__injectedProviders.get(port);
399
+ const provider = this.#injectedProviders.get(port);
379
400
  (0, util_1.assert)(provider, 'Cannot call pub(rpc.subscribe) before provider is set');
380
401
  return provider.send(request.method, request.params);
381
402
  }
382
403
  // Start a provider, return its meta
383
404
  rpcStartProvider(key, port) {
384
- (0, util_1.assert)(Object.keys(this.__internal__providers).includes(key), `Provider ${key} is not exposed by extension`);
385
- if (this.__internal__injectedProviders.get(port)) {
386
- return Promise.resolve(this.__internal__providers[key].meta);
405
+ (0, util_1.assert)(Object.keys(this.#providers).includes(key), `Provider ${key} is not exposed by extension`);
406
+ if (this.#injectedProviders.get(port)) {
407
+ return Promise.resolve(this.#providers[key].meta);
387
408
  }
388
409
  // Instantiate the provider
389
- this.__internal__injectedProviders.set(port, this.__internal__providers[key].start());
410
+ this.#injectedProviders.set(port, this.#providers[key].start());
390
411
  // Close provider connection when page is closed
391
412
  port.onDisconnect.addListener(() => {
392
- const provider = this.__internal__injectedProviders.get(port);
413
+ const provider = this.#injectedProviders.get(port);
393
414
  if (provider) {
394
415
  (0, helpers_js_1.withErrorLog)(() => provider.disconnect());
395
416
  }
396
- this.__internal__injectedProviders.delete(port);
417
+ this.#injectedProviders.delete(port);
397
418
  });
398
- return Promise.resolve(this.__internal__providers[key].meta);
419
+ return Promise.resolve(this.#providers[key].meta);
399
420
  }
400
421
  rpcSubscribe({ method, params, type }, cb, port) {
401
- const provider = this.__internal__injectedProviders.get(port);
422
+ const provider = this.#injectedProviders.get(port);
402
423
  (0, util_1.assert)(provider, 'Cannot call pub(rpc.subscribe) before provider is set');
403
424
  return provider.subscribe(type, method, params, cb);
404
425
  }
405
426
  rpcSubscribeConnected(_request, cb, port) {
406
- const provider = this.__internal__injectedProviders.get(port);
427
+ const provider = this.#injectedProviders.get(port);
407
428
  (0, util_1.assert)(provider, 'Cannot call pub(rpc.subscribeConnected) before provider is set');
408
429
  cb(null, provider.isConnected); // Immediately send back current isConnected
409
430
  provider.on('connected', () => cb(null, true));
410
431
  provider.on('disconnected', () => cb(null, false));
411
432
  }
412
433
  rpcUnsubscribe(request, port) {
413
- const provider = this.__internal__injectedProviders.get(port);
434
+ const provider = this.#injectedProviders.get(port);
414
435
  (0, util_1.assert)(provider, 'Cannot call pub(rpc.unsubscribe) before provider is set');
415
436
  return provider.unsubscribe(request.type, request.method, request.subscriptionId);
416
437
  }
417
438
  async saveMetadata(meta) {
418
- await this.__internal__metaStore.set(meta.genesisHash, meta);
439
+ await this.#metaStore.set(meta.genesisHash, meta);
419
440
  (0, extension_chains_1.addMetadata)(meta);
420
441
  }
421
442
  setNotification(notification) {
422
- this.__internal__notification = notification;
443
+ this.#notification = notification;
423
444
  return true;
424
445
  }
446
+ handleSignRequest(origin) {
447
+ const now = Date.now();
448
+ const lastTime = this.#lastRequestTimestamps.get(origin) || 0;
449
+ if (now - lastTime < this.#rateLimitInterval) {
450
+ throw new Error('Rate limit exceeded. Try again later.');
451
+ }
452
+ // If we're about to exceed max entries, evict the oldest
453
+ if (!this.#lastRequestTimestamps.has(origin) && this.#lastRequestTimestamps.size >= this.#maxEntries) {
454
+ const oldestKey = this.#lastRequestTimestamps.keys().next().value;
455
+ oldestKey && this.#lastRequestTimestamps.delete(oldestKey);
456
+ }
457
+ this.#lastRequestTimestamps.set(origin, now);
458
+ }
425
459
  sign(url, request, account) {
426
460
  const id = (0, getId_js_1.getId)();
461
+ try {
462
+ this.handleSignRequest(url);
463
+ }
464
+ catch (error) {
465
+ return Promise.reject(error);
466
+ }
427
467
  return new Promise((resolve, reject) => {
428
- this.__internal__signRequests[id] = {
468
+ this.#signRequests[id] = {
429
469
  ...this.signComplete(id, resolve, reject),
430
470
  account,
431
471
  id,
@@ -20,6 +20,7 @@ export default class Tabs {
20
20
  private rpcSubscribeConnected;
21
21
  private rpcUnsubscribe;
22
22
  private redirectPhishingLanding;
23
+ private parseUrl;
23
24
  private redirectIfPhishing;
24
25
  handle<TMessageType extends MessageTypes>(id: string, type: TMessageType, request: RequestTypes[TMessageType], url: string, port?: chrome.runtime.Port): Promise<ResponseTypes[keyof ResponseTypes]>;
25
26
  }
@@ -2,6 +2,7 @@
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  const tslib_1 = require("tslib");
4
4
  const rxjs_1 = require("rxjs");
5
+ const tldts_1 = require("tldts");
5
6
  const phishing_1 = require("@polkadot/phishing");
6
7
  const ui_keyring_1 = require("@polkadot/ui-keyring");
7
8
  const accounts_1 = require("@polkadot/ui-keyring/observable/accounts");
@@ -26,13 +27,13 @@ function transformAccounts(accounts, anyType = false) {
26
27
  }));
27
28
  }
28
29
  class Tabs {
29
- __internal__accountSubs = {};
30
- __internal__state;
30
+ #accountSubs = {};
31
+ #state;
31
32
  constructor(state) {
32
- this.__internal__state = state;
33
+ this.#state = state;
33
34
  }
34
35
  filterForAuthorizedAccounts(accounts, url) {
35
- const auth = this.__internal__state.authUrls[this.__internal__state.stripUrl(url)];
36
+ const auth = this.#state.authUrls[this.#state.stripUrl(url)];
36
37
  if (!auth) {
37
38
  return [];
38
39
  }
@@ -43,7 +44,7 @@ class Tabs {
43
44
  : auth.isAllowed);
44
45
  }
45
46
  authorize(url, request) {
46
- return this.__internal__state.authorizeUrl(url, request);
47
+ return this.#state.authorizeUrl(url, request);
47
48
  }
48
49
  accountsListAuthorized(url, { anyType }) {
49
50
  const transformedAccounts = transformAccounts(accounts_1.accounts.subject.getValue(), anyType);
@@ -51,13 +52,13 @@ class Tabs {
51
52
  }
52
53
  accountsSubscribeAuthorized(url, id, port) {
53
54
  const cb = (0, subscriptions_js_1.createSubscription)(id, port);
54
- const strippedUrl = this.__internal__state.stripUrl(url);
55
- const authUrlObservable = this.__internal__state.authUrlSubjects[strippedUrl]?.asObservable();
55
+ const strippedUrl = this.#state.stripUrl(url);
56
+ const authUrlObservable = this.#state.authUrlSubjects[strippedUrl]?.asObservable();
56
57
  if (!authUrlObservable) {
57
58
  console.error(`No authUrlSubject found for ${strippedUrl}`);
58
59
  return id;
59
60
  }
60
- this.__internal__accountSubs[id] = {
61
+ this.#accountSubs[id] = {
61
62
  subscription: (0, rxjs_1.combineLatest)([accounts_1.accounts.subject, authUrlObservable]).subscribe(([accounts, _authUrlInfo]) => {
62
63
  const transformedAccounts = transformAccounts(accounts);
63
64
  cb(this.filterForAuthorizedAccounts(transformedAccounts, url));
@@ -70,11 +71,11 @@ class Tabs {
70
71
  return id;
71
72
  }
72
73
  accountsUnsubscribe(url, { id }) {
73
- const sub = this.__internal__accountSubs[id];
74
+ const sub = this.#accountSubs[id];
74
75
  if (!sub || sub.url !== url) {
75
76
  return false;
76
77
  }
77
- delete this.__internal__accountSubs[id];
78
+ delete this.#accountSubs[id];
78
79
  (0, subscriptions_js_1.unsubscribe)(id);
79
80
  sub.subscription.unsubscribe();
80
81
  return true;
@@ -87,35 +88,35 @@ class Tabs {
87
88
  bytesSign(url, request) {
88
89
  const address = request.address;
89
90
  const pair = this.getSigningPair(address);
90
- return this.__internal__state.sign(url, new RequestBytesSign_js_1.default(request), { address, ...pair.meta });
91
+ return this.#state.sign(url, new RequestBytesSign_js_1.default(request), { address, ...pair.meta });
91
92
  }
92
93
  extrinsicSign(url, request) {
93
94
  const address = request.address;
94
95
  const pair = this.getSigningPair(address);
95
- return this.__internal__state.sign(url, new RequestExtrinsicSign_js_1.default(request), { address, ...pair.meta });
96
+ return this.#state.sign(url, new RequestExtrinsicSign_js_1.default(request), { address, ...pair.meta });
96
97
  }
97
98
  metadataProvide(url, request) {
98
- return this.__internal__state.injectMetadata(url, request);
99
+ return this.#state.injectMetadata(url, request);
99
100
  }
100
101
  metadataList(_url) {
101
- return this.__internal__state.knownMetadata.map(({ genesisHash, specVersion }) => ({
102
+ return this.#state.knownMetadata.map(({ genesisHash, specVersion }) => ({
102
103
  genesisHash,
103
104
  specVersion
104
105
  }));
105
106
  }
106
107
  rpcListProviders() {
107
- return this.__internal__state.rpcListProviders();
108
+ return this.#state.rpcListProviders();
108
109
  }
109
110
  rpcSend(request, port) {
110
- return this.__internal__state.rpcSend(request, port);
111
+ return this.#state.rpcSend(request, port);
111
112
  }
112
113
  rpcStartProvider(key, port) {
113
- return this.__internal__state.rpcStartProvider(key, port);
114
+ return this.#state.rpcStartProvider(key, port);
114
115
  }
115
116
  async rpcSubscribe(request, id, port) {
116
117
  const innerCb = (0, subscriptions_js_1.createSubscription)(id, port);
117
118
  const cb = (_error, data) => innerCb(data);
118
- const subscriptionId = await this.__internal__state.rpcSubscribe(request, cb, port);
119
+ const subscriptionId = await this.#state.rpcSubscribe(request, cb, port);
119
120
  port.onDisconnect.addListener(() => {
120
121
  (0, subscriptions_js_1.unsubscribe)(id);
121
122
  (0, helpers_js_1.withErrorLog)(() => this.rpcUnsubscribe({ ...request, subscriptionId }, port));
@@ -125,14 +126,14 @@ class Tabs {
125
126
  rpcSubscribeConnected(request, id, port) {
126
127
  const innerCb = (0, subscriptions_js_1.createSubscription)(id, port);
127
128
  const cb = (_error, data) => innerCb(data);
128
- this.__internal__state.rpcSubscribeConnected(request, cb, port);
129
+ this.#state.rpcSubscribeConnected(request, cb, port);
129
130
  port.onDisconnect.addListener(() => {
130
131
  (0, subscriptions_js_1.unsubscribe)(id);
131
132
  });
132
133
  return Promise.resolve(true);
133
134
  }
134
135
  async rpcUnsubscribe(request, port) {
135
- return this.__internal__state.rpcUnsubscribe(request, port);
136
+ return this.#state.rpcUnsubscribe(request, port);
136
137
  }
137
138
  redirectPhishingLanding(phishingWebsite) {
138
139
  const nonFragment = phishingWebsite.split('#')[0];
@@ -145,6 +146,19 @@ class Tabs {
145
146
  .forEach((id) => (0, helpers_js_1.withErrorLog)(() => chrome.tabs.update(id, { url })));
146
147
  });
147
148
  }
149
+ parseUrl(rawUrl) {
150
+ let from = 'extension';
151
+ if (rawUrl) {
152
+ try {
153
+ const { hostname } = (0, tldts_1.parse)(rawUrl);
154
+ from = hostname || '<unknown>'; // Only use the hostname
155
+ }
156
+ catch {
157
+ from = '<unknown>';
158
+ }
159
+ }
160
+ return from;
161
+ }
148
162
  async redirectIfPhishing(url) {
149
163
  const isInDenyList = await (0, phishing_1.checkIfDenied)(url);
150
164
  if (isInDenyList) {
@@ -155,10 +169,11 @@ class Tabs {
155
169
  }
156
170
  async handle(id, type, request, url, port) {
157
171
  if (type === 'pub(phishing.redirectIfDenied)') {
158
- return this.redirectIfPhishing(url);
172
+ const parsedUrl = this.parseUrl(url);
173
+ return this.redirectIfPhishing(parsedUrl);
159
174
  }
160
175
  if (type !== 'pub(authorize.tab)') {
161
- this.__internal__state.ensureUrlAuthorized(url);
176
+ this.#state.ensureUrlAuthorized(url);
162
177
  }
163
178
  switch (type) {
164
179
  case 'pub(authorize.tab)':
@@ -1,4 +1,4 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.packageInfo = void 0;
4
- exports.packageInfo = { name: '@polkadot/extension-base', path: typeof __dirname === 'string' ? __dirname : 'auto', type: 'cjs', version: '0.59.2' };
4
+ exports.packageInfo = { name: '@polkadot/extension-base', path: typeof __dirname === 'string' ? __dirname : 'auto', type: 'cjs', version: '0.61.1' };
@@ -10,19 +10,19 @@ let sendRequest;
10
10
  * @description Extension provider to be used by dapps
11
11
  */
12
12
  class PostMessageProvider {
13
- __internal__eventemitter;
13
+ #eventemitter;
14
14
  // Whether or not the actual extension background provider is connected
15
- __internal__isConnected = false;
15
+ #isConnected = false;
16
16
  // Subscription IDs are (historically) not guaranteed to be globally unique;
17
17
  // only unique for a given subscription method; which is why we identify
18
18
  // the subscriptions based on subscription id + type
19
- __internal__subscriptions = {}; // {[(type,subscriptionId)]: callback}
19
+ #subscriptions = {}; // {[(type,subscriptionId)]: callback}
20
20
  /**
21
21
  * @param {function} sendRequest The function to be called to send requests to the node
22
22
  * @param {function} subscriptionNotificationHandler Channel for receiving subscription messages
23
23
  */
24
24
  constructor(_sendRequest) {
25
- this.__internal__eventemitter = new eventemitter3_1.EventEmitter();
25
+ this.#eventemitter = new eventemitter3_1.EventEmitter();
26
26
  sendRequest = _sendRequest;
27
27
  }
28
28
  get isClonable() {
@@ -62,7 +62,7 @@ class PostMessageProvider {
62
62
  * @return {boolean} true if connected
63
63
  */
64
64
  get isConnected() {
65
- return this.__internal__isConnected;
65
+ return this.#isConnected;
66
66
  }
67
67
  listProviders() {
68
68
  return sendRequest('pub(rpc.listProviders)', undefined);
@@ -74,9 +74,9 @@ class PostMessageProvider {
74
74
  * @return unsubscribe function
75
75
  */
76
76
  on(type, sub) {
77
- this.__internal__eventemitter.on(type, sub);
77
+ this.#eventemitter.on(type, sub);
78
78
  return () => {
79
- this.__internal__eventemitter.removeListener(type, sub);
79
+ this.#eventemitter.removeListener(type, sub);
80
80
  };
81
81
  }
82
82
  // eslint-disable-next-line @typescript-eslint/no-explicit-any
@@ -86,7 +86,7 @@ class PostMessageProvider {
86
86
  const id = await sendRequest('pub(rpc.subscribe)', { method, params, type }, (res) => {
87
87
  subscription.callback(null, res);
88
88
  });
89
- this.__internal__subscriptions[`${type}::${id}`] = callback;
89
+ this.#subscriptions[`${type}::${id}`] = callback;
90
90
  return id;
91
91
  }
92
92
  return sendRequest('pub(rpc.send)', { method, params });
@@ -96,17 +96,17 @@ class PostMessageProvider {
96
96
  */
97
97
  async startProvider(key) {
98
98
  // Disconnect from the previous provider
99
- this.__internal__isConnected = false;
100
- this.__internal__eventemitter.emit('disconnected');
99
+ this.#isConnected = false;
100
+ this.#eventemitter.emit('disconnected');
101
101
  const meta = await sendRequest('pub(rpc.startProvider)', key);
102
102
  // eslint-disable-next-line @typescript-eslint/no-floating-promises
103
103
  sendRequest('pub(rpc.subscribeConnected)', null, (connected) => {
104
- this.__internal__isConnected = connected;
104
+ this.#isConnected = connected;
105
105
  if (connected) {
106
- this.__internal__eventemitter.emit('connected');
106
+ this.#eventemitter.emit('connected');
107
107
  }
108
108
  else {
109
- this.__internal__eventemitter.emit('disconnected');
109
+ this.#eventemitter.emit('disconnected');
110
110
  }
111
111
  return true;
112
112
  });
@@ -124,11 +124,11 @@ class PostMessageProvider {
124
124
  // the assigned id now does not match what the API user originally received. It has
125
125
  // a slight complication in solving - since we cannot rely on the send id, but rather
126
126
  // need to find the actual subscription id to map it
127
- if ((0, util_1.isUndefined)(this.__internal__subscriptions[subscription])) {
127
+ if ((0, util_1.isUndefined)(this.#subscriptions[subscription])) {
128
128
  l.debug(() => `Unable to find active subscription=${subscription}`);
129
129
  return false;
130
130
  }
131
- delete this.__internal__subscriptions[subscription];
131
+ delete this.#subscriptions[subscription];
132
132
  return this.send(method, [id]);
133
133
  }
134
134
  }