From aa5d99b1d258cd54d38db60aa0494b08510e28bf Mon Sep 17 00:00:00 2001 From: Francis O'Brien <42175565+F-OBrien@users.noreply.github.com> Date: Mon, 29 Jul 2024 12:06:17 +0100 Subject: [PATCH] Update subscribed accounts when connected site authorizations are modified (#1412) * Update subscribed accounts when connected site authorizations are modified * restore udateCurrentTabsUrl and mark as deprecated * lint --- .../src/background/handlers/Extension.ts | 2 +- .../src/background/handlers/State.ts | 40 +++++++++++++++---- .../src/background/handlers/Tabs.ts | 21 ++++++++-- 3 files changed, 52 insertions(+), 11 deletions(-) diff --git a/packages/extension-base/src/background/handlers/Extension.ts b/packages/extension-base/src/background/handlers/Extension.ts index 6af8984c0b..ca861e4378 100644 --- a/packages/extension-base/src/background/handlers/Extension.ts +++ b/packages/extension-base/src/background/handlers/Extension.ts @@ -529,7 +529,7 @@ export default class Extension { } private updateCurrentTabs ({ urls }: RequestActiveTabsUrlUpdate) { - this.#state.udateCurrentTabsUrl(urls); + this.#state.updateCurrentTabsUrl(urls); } private getConnectedTabsUrl () { diff --git a/packages/extension-base/src/background/handlers/State.ts b/packages/extension-base/src/background/handlers/State.ts index e2a1d84620..67c5e00724 100644 --- a/packages/extension-base/src/background/handlers/State.ts +++ b/packages/extension-base/src/background/handlers/State.ts @@ -154,6 +154,8 @@ export default class State { public readonly signSubject: BehaviorSubject = new BehaviorSubject([]); + public readonly authUrlSubjects: Record> = {}; + public defaultAuthAccountSelection: string[] = []; constructor (providers: Providers = {}) { @@ -169,6 +171,11 @@ export default class State { this.#authUrls = previousAuth; + // Initialize authUrlSubjects for each URL + Object.entries(previousAuth).forEach(([url, authInfo]) => { + this.authUrlSubjects[url] = new BehaviorSubject(authInfo); + }); + // retrieve previously set default auth accounts const storageDefaultAuthAccounts: Record = await chrome.storage.local.get(DEFAULT_AUTH_ACCOUNTS); const defaultAuthString: string = storageDefaultAuthAccounts?.[DEFAULT_AUTH_ACCOUNTS] || '[]'; @@ -215,10 +222,6 @@ export default class State { return this.#authUrls; } - private set authUrls (urls: AuthUrls) { - this.#authUrls = urls; - } - private popupClose (): void { this.#windows.forEach((id: number) => withErrorLog(() => chrome.windows.remove(id)) @@ -243,7 +246,9 @@ export default class State { const complete = async (authorizedAccounts: string[] = []) => { const { idStr, request: { origin }, url } = this.#authRequests[id]; - this.#authUrls[this.stripUrl(url)] = { + const strippedUrl = this.stripUrl(url); + + const authInfo: AuthUrlInfo = { authorizedAccounts, count: 0, id: idStr, @@ -251,6 +256,14 @@ export default class State { url }; + this.#authUrls[strippedUrl] = authInfo; + + if (!this.authUrlSubjects[strippedUrl]) { + this.authUrlSubjects[strippedUrl] = new BehaviorSubject(authInfo); + } else { + this.authUrlSubjects[strippedUrl].next(authInfo); + } + await this.saveCurrentAuthList(); await this.updateDefaultAuthAccounts(authorizedAccounts); delete this.#authRequests[id]; @@ -271,7 +284,14 @@ export default class State { }; }; + /** + * @deprecated This method is deprecated in favor of {@link updateCurrentTabs} and will be removed in a future release. + */ public udateCurrentTabsUrl (urls: string[]) { + this.updateCurrentTabsUrl(urls); + } + + public updateCurrentTabsUrl (urls: string[]) { const connectedTabs = urls.map((url) => { let strippedUrl = ''; @@ -385,6 +405,11 @@ export default class State { delete this.#authUrls[url]; await this.saveCurrentAuthList(); + if (this.authUrlSubjects[url]) { + entry.authorizedAccounts = []; + this.authUrlSubjects[url].next(entry); + } + return this.#authUrls; } @@ -403,9 +428,10 @@ export default class State { this.updateIcon(shouldClose); } - public async updateAuthorizedAccounts (authorizedAccountDiff: AuthorizedAccountsDiff): Promise { - authorizedAccountDiff.forEach(([url, authorizedAccountDiff]) => { + public async updateAuthorizedAccounts (authorizedAccountsDiff: AuthorizedAccountsDiff): Promise { + authorizedAccountsDiff.forEach(([url, authorizedAccountDiff]) => { this.#authUrls[url].authorizedAccounts = authorizedAccountDiff; + this.authUrlSubjects[url].next(this.#authUrls[url]); }); await this.saveCurrentAuthList(); diff --git a/packages/extension-base/src/background/handlers/Tabs.ts b/packages/extension-base/src/background/handlers/Tabs.ts index 58fd5e2a89..37b02afe0c 100644 --- a/packages/extension-base/src/background/handlers/Tabs.ts +++ b/packages/extension-base/src/background/handlers/Tabs.ts @@ -3,16 +3,17 @@ /* global chrome */ -import type { Subscription } from 'rxjs'; import type { InjectedAccount, InjectedMetadataKnown, MetadataDef, ProviderMeta } from '@polkadot/extension-inject/types'; import type { KeyringPair } from '@polkadot/keyring/types'; import type { JsonRpcResponse } from '@polkadot/rpc-provider/types'; import type { SignerPayloadJSON, SignerPayloadRaw } from '@polkadot/types/types'; import type { SubjectInfo } from '@polkadot/ui-keyring/observable/types'; -import type { MessageTypes, RequestAccountList, RequestAccountUnsubscribe, RequestAuthorizeTab, RequestRpcSend, RequestRpcSubscribe, RequestRpcUnsubscribe, RequestTypes, ResponseRpcListProviders, ResponseSigning, ResponseTypes, SubscriptionMessageTypes } from '../types.js'; +import type { AuthUrlInfo, MessageTypes, RequestAccountList, RequestAccountUnsubscribe, RequestAuthorizeTab, RequestRpcSend, RequestRpcSubscribe, RequestRpcUnsubscribe, RequestTypes, ResponseRpcListProviders, ResponseSigning, ResponseTypes, SubscriptionMessageTypes } from '../types.js'; import type { AuthResponse } from './State.js'; import type State from './State.js'; +import { combineLatest, type Subscription } from 'rxjs'; + import { checkIfDenied } from '@polkadot/phishing'; import { keyring } from '@polkadot/ui-keyring'; import { accounts as accountsObservable } from '@polkadot/ui-keyring/observable/accounts'; @@ -56,6 +57,10 @@ export default class Tabs { private filterForAuthorizedAccounts (accounts: InjectedAccount[], url: string): InjectedAccount[] { const auth = this.#state.authUrls[this.#state.stripUrl(url)]; + if (!auth) { + return []; + } + return accounts.filter( (allAcc) => auth.authorizedAccounts @@ -79,8 +84,18 @@ export default class Tabs { private accountsSubscribeAuthorized (url: string, id: string, port: chrome.runtime.Port): string { const cb = createSubscription<'pub(accounts.subscribe)'>(id, port); + const strippedUrl = this.#state.stripUrl(url); + + const authUrlObservable = this.#state.authUrlSubjects[strippedUrl]?.asObservable(); + + if (!authUrlObservable) { + console.error(`No authUrlSubject found for ${strippedUrl}`); + + return id; + } + this.#accountSubs[id] = { - subscription: accountsObservable.subject.subscribe((accounts: SubjectInfo): void => { + subscription: combineLatest([accountsObservable.subject, authUrlObservable]).subscribe(([accounts, _authUrlInfo]: [SubjectInfo, AuthUrlInfo]): void => { const transformedAccounts = transformAccounts(accounts); cb(this.filterForAuthorizedAccounts(transformedAccounts, url));