mirror of
https://github.com/bitwarden/browser.git
synced 2024-09-28 04:08:47 +02:00
[PM-2147] [BEEEP] Open login form used to unlock extension in a separate window instead of a tab (#5384)
* [PM-1796] The autofill keyboard shortcut does not prompt a user to unlock a locked extension within an incongito browsing session * [PM-1796] Implementing fixes for how we handle focus redirection when logging a user in and attempting to autofill within the Firefox Workspaces addon * [PM-1796] Removing the `openerTab` value from the createNewTab method within brwoserApi.ts * [PM-1796] Removing async declaration from createNewTab * [PM-1796] Removing unnecessary param from the call to openBitwardenExtrensionTab * [PM-2147] [BEEEP] Open login form used to unlock extension in a separate window instead of a tab * [PM-2147] [BEEEP] Open login form used to unlock extension in a separate window instead of a tab * [PM-2147] [BEEEP] Modifying the position where the window opens and starting cleanup of comments within implementation * [PM-2147] [BEEEP] Cleaning up comments within implementation * [PM-2147] [BEEEP] Removing unnecessary method * [PM-2147] [BEEEP] Removing package-lock changes * [PM-2147] [BEEEP] Cleaning up implementation * [PM-2147] [BEEEP] Reverting addition to the whitelist-capital-letters filter and updating named file * [PM-2147] [BEEEP] Reverting addition to the whitelist-capital-letters filter and updating named file * [PM-2147] [BEEEP] Adjusting implementation of notifications bar to trigger presentation on lock only when not adding a new vault item * [PM-2147] [BEEEP] Adjusting implementation of how we open a login prompt window to ensure we are showing the address bar to the user * [PM-2147] [BEEEP] Modifying the method closeBitwardenLoginPromptWindow to not check for a popup type window * [PM-2147] [BEEEP] Fixing bug where notification bar does not close when unlocking vault * [PM-2147] [BEEEP] Adjusting placement of method BrowserApi.getWindow to have it present closer to getTab * [PM-2147] [BEEEP] Implementing a sepearate service BrowserPopoutService that will maintain the most recently created popouts and selectively remove those when re-opening the login prompt * [PM-2147] [BEEEP] Modifying position of BrowserPopoutWindowService * [PM-2147] [BEEEP] Modifying position of BrowserPopoutWindowService * [PM-2147] [BEEEP] Modifying how we handle identifying a single use popout
This commit is contained in:
parent
a05b4fd094
commit
50b3e40a05
@ -630,6 +630,12 @@
|
|||||||
"notificationChangeSave": {
|
"notificationChangeSave": {
|
||||||
"message": "Update"
|
"message": "Update"
|
||||||
},
|
},
|
||||||
|
"notificationUnlockDesc": {
|
||||||
|
"message": "Unlock your Bitwarden vault to complete the auto-fill request."
|
||||||
|
},
|
||||||
|
"notificationUnlock": {
|
||||||
|
"message": "Unlock"
|
||||||
|
},
|
||||||
"enableContextMenuItem": {
|
"enableContextMenuItem": {
|
||||||
"message": "Show context menu options"
|
"message": "Show context menu options"
|
||||||
},
|
},
|
||||||
|
@ -30,6 +30,7 @@ export default class ContextMenusBackground {
|
|||||||
msg.data.commandToRetry.msg.data,
|
msg.data.commandToRetry.msg.data,
|
||||||
msg.data.commandToRetry.sender.tab
|
msg.data.commandToRetry.sender.tab
|
||||||
);
|
);
|
||||||
|
await BrowserApi.tabSendMessageData(sender.tab, "closeNotificationBar");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
@ -12,6 +12,7 @@ import { FolderService } from "@bitwarden/common/vault/abstractions/folder/folde
|
|||||||
import { CipherType } from "@bitwarden/common/vault/enums/cipher-type";
|
import { CipherType } from "@bitwarden/common/vault/enums/cipher-type";
|
||||||
import { CipherView } from "@bitwarden/common/vault/models/view/cipher.view";
|
import { CipherView } from "@bitwarden/common/vault/models/view/cipher.view";
|
||||||
|
|
||||||
|
import AddUnlockVaultQueueMessage from "../../background/models/add-unlock-vault-queue-message";
|
||||||
import AddChangePasswordQueueMessage from "../../background/models/addChangePasswordQueueMessage";
|
import AddChangePasswordQueueMessage from "../../background/models/addChangePasswordQueueMessage";
|
||||||
import AddLoginQueueMessage from "../../background/models/addLoginQueueMessage";
|
import AddLoginQueueMessage from "../../background/models/addLoginQueueMessage";
|
||||||
import AddLoginRuntimeMessage from "../../background/models/addLoginRuntimeMessage";
|
import AddLoginRuntimeMessage from "../../background/models/addLoginRuntimeMessage";
|
||||||
@ -23,7 +24,11 @@ import { BrowserStateService } from "../../platform/services/abstractions/browse
|
|||||||
import { AutofillService } from "../services/abstractions/autofill.service";
|
import { AutofillService } from "../services/abstractions/autofill.service";
|
||||||
|
|
||||||
export default class NotificationBackground {
|
export default class NotificationBackground {
|
||||||
private notificationQueue: (AddLoginQueueMessage | AddChangePasswordQueueMessage)[] = [];
|
private notificationQueue: (
|
||||||
|
| AddLoginQueueMessage
|
||||||
|
| AddChangePasswordQueueMessage
|
||||||
|
| AddUnlockVaultQueueMessage
|
||||||
|
)[] = [];
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
private autofillService: AutofillService,
|
private autofillService: AutofillService,
|
||||||
@ -53,10 +58,7 @@ export default class NotificationBackground {
|
|||||||
async processMessage(msg: any, sender: chrome.runtime.MessageSender) {
|
async processMessage(msg: any, sender: chrome.runtime.MessageSender) {
|
||||||
switch (msg.command) {
|
switch (msg.command) {
|
||||||
case "unlockCompleted":
|
case "unlockCompleted":
|
||||||
if (msg.data.target !== "notification.background") {
|
await this.handleUnlockCompleted(msg.data, sender);
|
||||||
return;
|
|
||||||
}
|
|
||||||
await this.processMessage(msg.data.commandToRetry.msg, msg.data.commandToRetry.sender);
|
|
||||||
break;
|
break;
|
||||||
case "bgGetDataForTab":
|
case "bgGetDataForTab":
|
||||||
await this.getDataForTab(sender.tab, msg.responseCommand);
|
await this.getDataForTab(sender.tab, msg.responseCommand);
|
||||||
@ -82,7 +84,9 @@ export default class NotificationBackground {
|
|||||||
if ((await this.authService.getAuthStatus()) < AuthenticationStatus.Unlocked) {
|
if ((await this.authService.getAuthStatus()) < AuthenticationStatus.Unlocked) {
|
||||||
const retryMessage: LockedVaultPendingNotificationsItem = {
|
const retryMessage: LockedVaultPendingNotificationsItem = {
|
||||||
commandToRetry: {
|
commandToRetry: {
|
||||||
msg: msg,
|
msg: {
|
||||||
|
command: msg,
|
||||||
|
},
|
||||||
sender: sender,
|
sender: sender,
|
||||||
},
|
},
|
||||||
target: "notification.background",
|
target: "notification.background",
|
||||||
@ -114,6 +118,9 @@ export default class NotificationBackground {
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
case "promptForLogin":
|
||||||
|
await this.unlockVault(sender.tab);
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -181,6 +188,14 @@ export default class NotificationBackground {
|
|||||||
webVaultURL: await this.environmentService.getWebVaultUrl(),
|
webVaultURL: await this.environmentService.getWebVaultUrl(),
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
} else if (this.notificationQueue[i].type === NotificationQueueMessageType.UnlockVault) {
|
||||||
|
BrowserApi.tabSendMessageData(tab, "openNotificationBar", {
|
||||||
|
type: "unlock",
|
||||||
|
typeData: {
|
||||||
|
isVaultLocked: this.notificationQueue[i].wasVaultLocked,
|
||||||
|
theme: await this.getCurrentTheme(),
|
||||||
|
},
|
||||||
|
});
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -305,6 +320,20 @@ export default class NotificationBackground {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private async unlockVault(tab: chrome.tabs.Tab) {
|
||||||
|
const currentAuthStatus = await this.authService.getAuthStatus();
|
||||||
|
if (currentAuthStatus !== AuthenticationStatus.Locked || this.notificationQueue.length) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const loginDomain = Utils.getDomain(tab.url);
|
||||||
|
if (!loginDomain) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.pushUnlockVaultToQueue(loginDomain, tab);
|
||||||
|
}
|
||||||
|
|
||||||
private async pushChangePasswordToQueue(
|
private async pushChangePasswordToQueue(
|
||||||
cipherId: string,
|
cipherId: string,
|
||||||
loginDomain: string,
|
loginDomain: string,
|
||||||
@ -327,6 +356,20 @@ export default class NotificationBackground {
|
|||||||
await this.checkNotificationQueue(tab);
|
await this.checkNotificationQueue(tab);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private async pushUnlockVaultToQueue(loginDomain: string, tab: chrome.tabs.Tab) {
|
||||||
|
this.removeTabFromNotificationQueue(tab);
|
||||||
|
const message: AddUnlockVaultQueueMessage = {
|
||||||
|
type: NotificationQueueMessageType.UnlockVault,
|
||||||
|
domain: loginDomain,
|
||||||
|
tabId: tab.id,
|
||||||
|
expires: new Date(new Date().getTime() + 0.5 * 60000), // 30 seconds
|
||||||
|
wasVaultLocked: true,
|
||||||
|
};
|
||||||
|
this.notificationQueue.push(message);
|
||||||
|
await this.checkNotificationQueue(tab);
|
||||||
|
this.removeTabFromNotificationQueue(tab);
|
||||||
|
}
|
||||||
|
|
||||||
private async saveOrUpdateCredentials(tab: chrome.tabs.Tab, edit: boolean, folderId?: string) {
|
private async saveOrUpdateCredentials(tab: chrome.tabs.Tab, edit: boolean, folderId?: string) {
|
||||||
for (let i = this.notificationQueue.length - 1; i >= 0; i--) {
|
for (let i = this.notificationQueue.length - 1; i >= 0; i--) {
|
||||||
const queueMessage = this.notificationQueue[i];
|
const queueMessage = this.notificationQueue[i];
|
||||||
@ -463,4 +506,22 @@ export default class NotificationBackground {
|
|||||||
this.policyService.policyAppliesToActiveUser$(PolicyType.PersonalOwnership)
|
this.policyService.policyAppliesToActiveUser$(PolicyType.PersonalOwnership)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private async handleUnlockCompleted(
|
||||||
|
messageData: LockedVaultPendingNotificationsItem,
|
||||||
|
sender: chrome.runtime.MessageSender
|
||||||
|
): Promise<void> {
|
||||||
|
if (messageData.commandToRetry.msg.command === "autofill_login") {
|
||||||
|
await BrowserApi.tabSendMessageData(sender.tab, "closeNotificationBar");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (messageData.target !== "notification.background") {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
await this.processMessage(
|
||||||
|
messageData.commandToRetry.msg.command,
|
||||||
|
messageData.commandToRetry.sender
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -51,4 +51,13 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
|
<template id="template-unlock">
|
||||||
|
<div class="inner-wrapper">
|
||||||
|
<div id="unlock-text"></div>
|
||||||
|
<div>
|
||||||
|
<button type="button" id="unlock-vault" class="primary"></button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
</html>
|
</html>
|
||||||
|
@ -28,6 +28,8 @@ function load() {
|
|||||||
notificationEdit: chrome.i18n.getMessage("edit"),
|
notificationEdit: chrome.i18n.getMessage("edit"),
|
||||||
notificationChangeSave: chrome.i18n.getMessage("notificationChangeSave"),
|
notificationChangeSave: chrome.i18n.getMessage("notificationChangeSave"),
|
||||||
notificationChangeDesc: chrome.i18n.getMessage("notificationChangeDesc"),
|
notificationChangeDesc: chrome.i18n.getMessage("notificationChangeDesc"),
|
||||||
|
notificationUnlock: chrome.i18n.getMessage("notificationUnlock"),
|
||||||
|
notificationUnlockDesc: chrome.i18n.getMessage("notificationUnlockDesc"),
|
||||||
};
|
};
|
||||||
|
|
||||||
const logoLink = document.getElementById("logo-link") as HTMLAnchorElement;
|
const logoLink = document.getElementById("logo-link") as HTMLAnchorElement;
|
||||||
@ -72,6 +74,13 @@ function load() {
|
|||||||
|
|
||||||
changeTemplate.content.getElementById("change-text").textContent = i18n.notificationChangeDesc;
|
changeTemplate.content.getElementById("change-text").textContent = i18n.notificationChangeDesc;
|
||||||
|
|
||||||
|
const unlockTemplate = document.getElementById("template-unlock") as HTMLTemplateElement;
|
||||||
|
|
||||||
|
const unlockButton = unlockTemplate.content.getElementById("unlock-vault");
|
||||||
|
unlockButton.textContent = i18n.notificationUnlock;
|
||||||
|
|
||||||
|
unlockTemplate.content.getElementById("unlock-text").textContent = i18n.notificationUnlockDesc;
|
||||||
|
|
||||||
// i18n for body content
|
// i18n for body content
|
||||||
const closeButton = document.getElementById("close-button");
|
const closeButton = document.getElementById("close-button");
|
||||||
closeButton.title = i18n.close;
|
closeButton.title = i18n.close;
|
||||||
@ -80,6 +89,8 @@ function load() {
|
|||||||
handleTypeAdd();
|
handleTypeAdd();
|
||||||
} else if (getQueryVariable("type") === "change") {
|
} else if (getQueryVariable("type") === "change") {
|
||||||
handleTypeChange();
|
handleTypeChange();
|
||||||
|
} else if (getQueryVariable("type") === "unlock") {
|
||||||
|
handleTypeUnlock();
|
||||||
}
|
}
|
||||||
|
|
||||||
closeButton.addEventListener("click", (e) => {
|
closeButton.addEventListener("click", (e) => {
|
||||||
@ -172,6 +183,17 @@ function handleTypeChange() {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function handleTypeUnlock() {
|
||||||
|
setContent(document.getElementById("template-unlock") as HTMLTemplateElement);
|
||||||
|
|
||||||
|
const unlockButton = document.getElementById("unlock-vault");
|
||||||
|
unlockButton.addEventListener("click", (e) => {
|
||||||
|
sendPlatformMessage({
|
||||||
|
command: "bgReopenPromptForLogin",
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
function setContent(template: HTMLTemplateElement) {
|
function setContent(template: HTMLTemplateElement) {
|
||||||
const content = document.getElementById("content");
|
const content = document.getElementById("content");
|
||||||
while (content.firstChild) {
|
while (content.firstChild) {
|
||||||
|
@ -114,6 +114,7 @@ import { Account } from "../models/account";
|
|||||||
import { BrowserApi } from "../platform/browser/browser-api";
|
import { BrowserApi } from "../platform/browser/browser-api";
|
||||||
import { flagEnabled } from "../platform/flags";
|
import { flagEnabled } from "../platform/flags";
|
||||||
import { UpdateBadge } from "../platform/listeners/update-badge";
|
import { UpdateBadge } from "../platform/listeners/update-badge";
|
||||||
|
import BrowserPopoutWindowService from "../platform/popup/browser-popout-window.service";
|
||||||
import { BrowserStateService as StateServiceAbstraction } from "../platform/services/abstractions/browser-state.service";
|
import { BrowserStateService as StateServiceAbstraction } from "../platform/services/abstractions/browser-state.service";
|
||||||
import { BrowserCryptoService } from "../platform/services/browser-crypto.service";
|
import { BrowserCryptoService } from "../platform/services/browser-crypto.service";
|
||||||
import { BrowserEnvironmentService } from "../platform/services/browser-environment.service";
|
import { BrowserEnvironmentService } from "../platform/services/browser-environment.service";
|
||||||
@ -195,6 +196,7 @@ export default class MainBackground {
|
|||||||
cipherContextMenuHandler: CipherContextMenuHandler;
|
cipherContextMenuHandler: CipherContextMenuHandler;
|
||||||
configService: ConfigServiceAbstraction;
|
configService: ConfigServiceAbstraction;
|
||||||
configApiService: ConfigApiServiceAbstraction;
|
configApiService: ConfigApiServiceAbstraction;
|
||||||
|
browserPopoutWindowService: BrowserPopoutWindowService;
|
||||||
|
|
||||||
// Passed to the popup for Safari to workaround issues with theming, downloading, etc.
|
// Passed to the popup for Safari to workaround issues with theming, downloading, etc.
|
||||||
backgroundWindow = window;
|
backgroundWindow = window;
|
||||||
@ -512,6 +514,7 @@ export default class MainBackground {
|
|||||||
this.authService,
|
this.authService,
|
||||||
this.environmentService
|
this.environmentService
|
||||||
);
|
);
|
||||||
|
this.browserPopoutWindowService = new BrowserPopoutWindowService();
|
||||||
|
|
||||||
const systemUtilsServiceReloadCallback = () => {
|
const systemUtilsServiceReloadCallback = () => {
|
||||||
const forceWindowReload =
|
const forceWindowReload =
|
||||||
@ -543,7 +546,8 @@ export default class MainBackground {
|
|||||||
this.environmentService,
|
this.environmentService,
|
||||||
this.messagingService,
|
this.messagingService,
|
||||||
this.logService,
|
this.logService,
|
||||||
this.configService
|
this.configService,
|
||||||
|
this.browserPopoutWindowService
|
||||||
);
|
);
|
||||||
this.nativeMessagingBackground = new NativeMessagingBackground(
|
this.nativeMessagingBackground = new NativeMessagingBackground(
|
||||||
this.cryptoService,
|
this.cryptoService,
|
||||||
|
@ -0,0 +1,6 @@
|
|||||||
|
import NotificationQueueMessage from "./notificationQueueMessage";
|
||||||
|
import { NotificationQueueMessageType } from "./notificationQueueMessageType";
|
||||||
|
|
||||||
|
export default class AddUnlockVaultQueueMessage extends NotificationQueueMessage {
|
||||||
|
type: NotificationQueueMessageType.UnlockVault;
|
||||||
|
}
|
@ -1,6 +1,9 @@
|
|||||||
export default class LockedVaultPendingNotificationsItem {
|
export default class LockedVaultPendingNotificationsItem {
|
||||||
commandToRetry: {
|
commandToRetry: {
|
||||||
msg: any;
|
msg: {
|
||||||
|
command: string;
|
||||||
|
data?: any;
|
||||||
|
};
|
||||||
sender: chrome.runtime.MessageSender;
|
sender: chrome.runtime.MessageSender;
|
||||||
};
|
};
|
||||||
target: string;
|
target: string;
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
export enum NotificationQueueMessageType {
|
export enum NotificationQueueMessageType {
|
||||||
AddLogin = 0,
|
AddLogin = 0,
|
||||||
ChangePassword = 1,
|
ChangePassword = 1,
|
||||||
|
UnlockVault = 2,
|
||||||
}
|
}
|
||||||
|
@ -8,6 +8,7 @@ import { Utils } from "@bitwarden/common/platform/misc/utils";
|
|||||||
|
|
||||||
import { AutofillService } from "../autofill/services/abstractions/autofill.service";
|
import { AutofillService } from "../autofill/services/abstractions/autofill.service";
|
||||||
import { BrowserApi } from "../platform/browser/browser-api";
|
import { BrowserApi } from "../platform/browser/browser-api";
|
||||||
|
import { BrowserPopoutWindowService } from "../platform/popup/abstractions/browser-popout-window.service";
|
||||||
import { BrowserEnvironmentService } from "../platform/services/browser-environment.service";
|
import { BrowserEnvironmentService } from "../platform/services/browser-environment.service";
|
||||||
import BrowserPlatformUtilsService from "../platform/services/browser-platform-utils.service";
|
import BrowserPlatformUtilsService from "../platform/services/browser-platform-utils.service";
|
||||||
|
|
||||||
@ -30,7 +31,8 @@ export default class RuntimeBackground {
|
|||||||
private environmentService: BrowserEnvironmentService,
|
private environmentService: BrowserEnvironmentService,
|
||||||
private messagingService: MessagingService,
|
private messagingService: MessagingService,
|
||||||
private logService: LogService,
|
private logService: LogService,
|
||||||
private configService: ConfigServiceAbstraction
|
private configService: ConfigServiceAbstraction,
|
||||||
|
private browserPopoutWindowService: BrowserPopoutWindowService
|
||||||
) {
|
) {
|
||||||
// onInstalled listener must be wired up before anything else, so we do it in the ctor
|
// onInstalled listener must be wired up before anything else, so we do it in the ctor
|
||||||
chrome.runtime.onInstalled.addListener((details: any) => {
|
chrome.runtime.onInstalled.addListener((details: any) => {
|
||||||
@ -66,7 +68,7 @@ export default class RuntimeBackground {
|
|||||||
|
|
||||||
if (this.lockedVaultPendingNotifications?.length > 0) {
|
if (this.lockedVaultPendingNotifications?.length > 0) {
|
||||||
item = this.lockedVaultPendingNotifications.pop();
|
item = this.lockedVaultPendingNotifications.pop();
|
||||||
BrowserApi.closeBitwardenExtensionTab();
|
await this.browserPopoutWindowService.closeLoginPrompt();
|
||||||
}
|
}
|
||||||
|
|
||||||
await this.main.refreshBadge();
|
await this.main.refreshBadge();
|
||||||
@ -105,7 +107,8 @@ export default class RuntimeBackground {
|
|||||||
await this.main.openPopup();
|
await this.main.openPopup();
|
||||||
break;
|
break;
|
||||||
case "promptForLogin":
|
case "promptForLogin":
|
||||||
BrowserApi.openBitwardenExtensionTab("popup/index.html", true);
|
case "bgReopenPromptForLogin":
|
||||||
|
await this.browserPopoutWindowService.openLoginPrompt(sender.tab?.windowId);
|
||||||
break;
|
break;
|
||||||
case "openAddEditCipher": {
|
case "openAddEditCipher": {
|
||||||
const addEditCipherUrl =
|
const addEditCipherUrl =
|
||||||
|
@ -17,6 +17,24 @@ export class BrowserApi {
|
|||||||
return chrome.runtime.getManifest().manifest_version;
|
return chrome.runtime.getManifest().manifest_version;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static getWindow(windowId?: number): Promise<chrome.windows.Window> | void {
|
||||||
|
if (!windowId) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
return new Promise((resolve) =>
|
||||||
|
chrome.windows.get(windowId, { populate: true }, (window) => resolve(window))
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
static async createWindow(options: chrome.windows.CreateData): Promise<chrome.windows.Window> {
|
||||||
|
return new Promise((resolve) =>
|
||||||
|
chrome.windows.create(options, (window) => {
|
||||||
|
resolve(window);
|
||||||
|
})
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
static async getTabFromCurrentWindowId(): Promise<chrome.tabs.Tab> | null {
|
static async getTabFromCurrentWindowId(): Promise<chrome.tabs.Tab> | null {
|
||||||
return await BrowserApi.tabsQueryFirst({
|
return await BrowserApi.tabsQueryFirst({
|
||||||
active: true,
|
active: true,
|
||||||
@ -105,6 +123,10 @@ export class BrowserApi {
|
|||||||
chrome.tabs.sendMessage<TabMessage, T>(tabId, message, options, responseCallback);
|
chrome.tabs.sendMessage<TabMessage, T>(tabId, message, options, responseCallback);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static async removeTab(tabId: number) {
|
||||||
|
await chrome.tabs.remove(tabId);
|
||||||
|
}
|
||||||
|
|
||||||
static async getPrivateModeWindows(): Promise<browser.windows.Window[]> {
|
static async getPrivateModeWindows(): Promise<browser.windows.Window[]> {
|
||||||
return (await browser.windows.getAll()).filter((win) => win.incognito);
|
return (await browser.windows.getAll()).filter((win) => win.incognito);
|
||||||
}
|
}
|
||||||
@ -165,7 +187,7 @@ export class BrowserApi {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const tabToClose = tabs[tabs.length - 1];
|
const tabToClose = tabs[tabs.length - 1];
|
||||||
chrome.tabs.remove(tabToClose.id);
|
BrowserApi.removeTab(tabToClose.id);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static registeredMessageListeners: any[] = [];
|
private static registeredMessageListeners: any[] = [];
|
||||||
|
@ -0,0 +1,6 @@
|
|||||||
|
interface BrowserPopoutWindowService {
|
||||||
|
openLoginPrompt(senderWindowId: number): Promise<void>;
|
||||||
|
closeLoginPrompt(): Promise<void>;
|
||||||
|
}
|
||||||
|
|
||||||
|
export { BrowserPopoutWindowService };
|
@ -0,0 +1,64 @@
|
|||||||
|
import { BrowserApi } from "../browser/browser-api";
|
||||||
|
|
||||||
|
import { BrowserPopoutWindowService as BrowserPopupWindowServiceInterface } from "./abstractions/browser-popout-window.service";
|
||||||
|
|
||||||
|
class BrowserPopoutWindowService implements BrowserPopupWindowServiceInterface {
|
||||||
|
private singleActionPopoutTabIds: Record<string, number> = {};
|
||||||
|
private defaultPopoutWindowOptions: chrome.windows.CreateData = {
|
||||||
|
type: "normal",
|
||||||
|
focused: true,
|
||||||
|
width: 500,
|
||||||
|
height: 800,
|
||||||
|
};
|
||||||
|
|
||||||
|
async openLoginPrompt(senderWindowId: number) {
|
||||||
|
await this.closeLoginPrompt();
|
||||||
|
await this.openPopoutWindow(
|
||||||
|
senderWindowId,
|
||||||
|
"popup/index.html?uilocation=popout",
|
||||||
|
"loginPrompt"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
async closeLoginPrompt() {
|
||||||
|
await this.closeSingleActionPopout("loginPrompt");
|
||||||
|
}
|
||||||
|
|
||||||
|
private async openPopoutWindow(
|
||||||
|
senderWindowId: number,
|
||||||
|
popupWindowURL: string,
|
||||||
|
singleActionPopoutKey: string
|
||||||
|
) {
|
||||||
|
const senderWindow = senderWindowId && (await BrowserApi.getWindow(senderWindowId));
|
||||||
|
const url = chrome.extension.getURL(popupWindowURL);
|
||||||
|
const offsetRight = 15;
|
||||||
|
const offsetTop = 90;
|
||||||
|
const popupWidth = this.defaultPopoutWindowOptions.width;
|
||||||
|
const windowOptions = senderWindow
|
||||||
|
? {
|
||||||
|
...this.defaultPopoutWindowOptions,
|
||||||
|
url,
|
||||||
|
left: senderWindow.left + senderWindow.width - popupWidth - offsetRight,
|
||||||
|
top: senderWindow.top + offsetTop,
|
||||||
|
}
|
||||||
|
: { ...this.defaultPopoutWindowOptions, url };
|
||||||
|
|
||||||
|
const popupWindow = await BrowserApi.createWindow(windowOptions);
|
||||||
|
|
||||||
|
if (!singleActionPopoutKey) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
this.singleActionPopoutTabIds[singleActionPopoutKey] = popupWindow?.tabs[0].id;
|
||||||
|
}
|
||||||
|
|
||||||
|
private async closeSingleActionPopout(popoutKey: string) {
|
||||||
|
const tabId = this.singleActionPopoutTabIds[popoutKey];
|
||||||
|
if (!tabId) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
await BrowserApi.removeTab(tabId);
|
||||||
|
this.singleActionPopoutTabIds[popoutKey] = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export default BrowserPopoutWindowService;
|
Loading…
Reference in New Issue
Block a user