Skip to content

Commit

Permalink
#7618: increase managed storage delay and link extension immediately …
Browse files Browse the repository at this point in the history
…for CWS installs (#7628)
  • Loading branch information
twschiller authored Feb 15, 2024
1 parent c918748 commit 963c1fd
Show file tree
Hide file tree
Showing 7 changed files with 221 additions and 68 deletions.
10 changes: 10 additions & 0 deletions src/background/background.ts
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,16 @@ import { initRuntimeLogging } from "@/development/runtimeLogging";
import initWalkthroughModalTrigger from "@/background/walkthroughModalTrigger";
import { initSidePanel } from "./sidePanel";
import initRestrictUnauthenticatedUrlAccess from "@/background/restrictUnauthenticatedUrlAccess";
import {
initManagedStorage,
watchDelayedStorageInitialization,
} from "@/store/enterprise/managedStorage";

// Try to initialize managed storage as early as possible because it impacts background behavior
// Call watchDelayedStorageInitialization to handle case where storage is not immediately available within timeout.
// We might consider putting watchStorageInitialization in initManagedStorage, but having a non-terminating
// interval complicates testing.
void initManagedStorage().then(async () => watchDelayedStorageInitialization());

void initLocator();
void initMessengerLogging();
Expand Down
2 changes: 1 addition & 1 deletion src/background/deploymentUpdater.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -416,7 +416,7 @@ describe("updateDeployments", () => {
expect(jest.mocked(uninstallAllDeployments).mock.calls).toHaveLength(0);
expect(refreshRegistriesMock.mock.calls).toHaveLength(0);
expect(saveSettingsStateMock).toHaveBeenCalledTimes(0);
});
}, 10_000);

test("do not open options page on update if restricted-version flag not set", async () => {
isLinkedMock.mockResolvedValue(true);
Expand Down
2 changes: 1 addition & 1 deletion src/background/deploymentUpdater.ts
Original file line number Diff line number Diff line change
Expand Up @@ -421,7 +421,7 @@ export async function updateDeployments(): Promise<void> {
sso: false,
});

void browser.runtime.openOptionsPage();
await browser.runtime.openOptionsPage();

return;
}
Expand Down
61 changes: 53 additions & 8 deletions src/background/installer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,10 @@ import { getExtensionToken, getUserData, isLinked } from "@/auth/token";
import { isCommunityControlRoom } from "@/contrib/automationanywhere/aaUtils";
import { isEmpty } from "lodash";
import { expectContext } from "@/utils/expectContext";
import { readManagedStorage } from "@/store/enterprise/managedStorage";
import {
readManagedStorage,
isInitialized as isManagedStorageInitialized,
} from "@/store/enterprise/managedStorage";
import { Events } from "@/telemetry/events";

import { DEFAULT_SERVICE_URL, UNINSTALL_URL } from "@/urlConstants";
Expand All @@ -40,6 +43,35 @@ import { getExtensionConsoleUrl } from "@/utils/extensionUtils";
*/
let _availableVersion: string | null = null;

/**
* Returns true if this appears to be a Chrome Web Store install and/or the user has an app URL where they're
* authenticated so the extension can be linked.
*/
async function isLikelyEndUserInstall(): Promise<boolean> {
// Query existing app/CWS tabs: https://developer.chrome.com/docs/extensions/reference/api/tabs#method-query
// `browser.tabs.query` supports https://developer.chrome.com/docs/extensions/develop/concepts/match-patterns
const likelyOnboardingTabs = await browser.tabs.query({
// Can't use SERVICE_URL directly because it contains a port number during development, resulting in an
// invalid URL match pattern
url: [
// Setup page is page before sending user to the CWS
new URL("setup", DEFAULT_SERVICE_URL).href,
// Base page is extension linking page. Needs path to be a valid URL match pattern
new URL("", DEFAULT_SERVICE_URL).href,
// Known CWS URLs: https://docs.pixiebrix.com/enterprise-it-setup/network-email-firewall-configuration
"https://chromewebstore.google.com/*",
"https://chrome.google.com/webstore/*",
],
});

// The CWS install URL differs based on the extension listing slug. So instead, only match on the runtime id.
return likelyOnboardingTabs.some(
(tab) =>
tab.url.includes(DEFAULT_SERVICE_URL) ||
tab.url.includes(browser.runtime.id),
);
}

/**
* Install handler to complete authentication configuration for the extension.
*/
Expand Down Expand Up @@ -127,7 +159,7 @@ export async function openInstallPage() {
active: true,
});
} else {
// Case 3: there's no Admin Console onboarding tab open
// Case 3: there's no Admin Console onboarding tab open.
//
// Open a new Admin Console tab which will automatically "links" the extension (by passing the native PixieBrix
// token to the extension).
Expand Down Expand Up @@ -199,18 +231,31 @@ export async function handleInstall({
// XXX: under what conditions could onInstalled fire, but the extension is already linked? Is this the case during
// development/loading an update of the extension from the file system?
if (!(await isLinked())) {
// PERFORMANCE: readManagedStorageByKey waits up to 2 seconds for managed storage to be available. Shouldn't be
// notice-able for end-user relative to the extension download/install time
const { ssoUrl, partnerId, controlRoomUrl, disableLoginTab } =
await readManagedStorage();
// If an end-user appears to be installing, jump to linking directly vs. waiting for readManagedStorage because
// readManagedStorage will wait until a timeout for managed storage to be available.
if (!isManagedStorageInitialized() && (await isLikelyEndUserInstall())) {
console.debug("Skipping readManagedStorage for end-user install");

await openInstallPage();
return;
}

// Reminder: readManagedStorage waits up to 4.5 seconds for managed storage to be available
const {
ssoUrl,
partnerId,
controlRoomUrl,
disableLoginTab,
managedOrganizationId,
} = await readManagedStorage();

if (disableLoginTab) {
// IT manager has disabled the login tab
return;
}

if (ssoUrl) {
// Don't launch the SSO page automatically. The SSO flow will be launched by deploymentUpdater.ts:updateDeployments
if (ssoUrl || managedOrganizationId) {
// Don't launch the page automatically. The SSO flow will be launched by deploymentUpdater.ts:updateDeployments
return;
}

Expand Down
Loading

0 comments on commit 963c1fd

Please sign in to comment.