tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

commit 92325e1fa4edd0ece34dc0ecbdf34536303ead1c
parent e046b7fef69c08c01cb2f8dd0b998d0968ff419b
Author: Punam Dahiya <pdahiya@mozilla.com>
Date:   Tue, 23 Dec 2025 20:17:31 +0000

Bug 2007177 - Implement SpecialMessageAction to invoke Accounts Authentication flow r=ai-frontend-reviewers,omc-reviewers,czhou,jprickett

Differential Revision: https://phabricator.services.mozilla.com/D277236

Diffstat:
Abrowser/components/aiwindow/ui/modules/AIWindowAccountAuth.sys.mjs | 113+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Mbrowser/components/aiwindow/ui/moz.build | 1+
Mtoolkit/components/messaging-system/lib/SpecialMessageActions.sys.mjs | 6++++++
Mtoolkit/components/messaging-system/schemas/SpecialMessageActionSchemas/SpecialMessageActionSchemas.json | 12++++++++++++
Mtoolkit/components/messaging-system/schemas/SpecialMessageActionSchemas/index.md | 8++++++++
Mtoolkit/components/messaging-system/schemas/SpecialMessageActionSchemas/test/browser/browser.toml | 2++
Atoolkit/components/messaging-system/schemas/SpecialMessageActionSchemas/test/browser/browser_sma_fxa_aiwindow_signin_flow.js | 30++++++++++++++++++++++++++++++
7 files changed, 172 insertions(+), 0 deletions(-)

diff --git a/browser/components/aiwindow/ui/modules/AIWindowAccountAuth.sys.mjs b/browser/components/aiwindow/ui/modules/AIWindowAccountAuth.sys.mjs @@ -0,0 +1,113 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +import { XPCOMUtils } from "resource://gre/modules/XPCOMUtils.sys.mjs"; + +const lazy = {}; + +ChromeUtils.defineESModuleGetters(lazy, { + SpecialMessageActions: + "resource://messaging-system/lib/SpecialMessageActions.sys.mjs", +}); + +ChromeUtils.defineLazyGetter(lazy, "fxAccounts", () => { + return ChromeUtils.importESModule( + "resource://gre/modules/FxAccounts.sys.mjs" + ).getFxAccountsSingleton(); +}); + +ChromeUtils.defineLazyGetter(lazy, "log", function () { + return console.createInstance({ + prefix: "AIWindowAccountAuth", + maxLogLevelPref: Services.prefs.getBoolPref("browser.aiwindow.log", false) + ? "Debug" + : "Warn", + }); +}); + +// Temporary gating while feature is in development +// To be set to true by default before MVP launch +XPCOMUtils.defineLazyPreferenceGetter( + lazy, + "AIWindowRequireSignIn", + "browser.aiwindow.requireSignIn", + false +); +XPCOMUtils.defineLazyPreferenceGetter( + lazy, + "hasAIWindowToSConsent", + "browser.aiwindow.tos.hasConsent", + false +); + +export const AIWindowAccountAuth = { + get hasToSConsent() { + return lazy.hasAIWindowToSConsent; + }, + + set hasToSConsent(value) { + Services.prefs.setBoolPref("browser.aiwindow.tos.hasConsent", value); + }, + + async isSignedIn() { + try { + const userData = await lazy.fxAccounts.getSignedInUser(); + return !!userData; + } catch (error) { + lazy.log.error("Error checking sign-in status:", error); + return false; + } + }, + + requiresSignIn() { + return lazy.AIWindowRequireSignIn; + }, + + async canAccessAIWindow() { + if (!this.requiresSignIn()) { + return true; + } + if (!this.hasToSConsent) { + return false; + } + return await this.isSignedIn(); + }, + + async promptSignIn(browser) { + try { + const data = { + autoClose: false, + entrypoint: "aiwindow", + extraParams: { + service: "aiwindow", + }, + }; + const signedIn = await lazy.SpecialMessageActions.fxaSignInFlow( + data, + browser + ); + if (signedIn) { + this.hasToSConsent = true; + } + return signedIn; + } catch (error) { + lazy.log.error("Error prompting sign-in:", error); + throw error; + } + }, + + async launchAIWindow(browser) { + if (!(await this.canAccessAIWindow())) { + const signedIn = await this.promptSignIn(browser); + if (!signedIn) { + lazy.log.error("User did not sign in successfully."); + return false; + } + } + // Proceed with launching the AI window + // Tobe updated with window switching toggleWindow call implemented with fix of bug 2006469 + browser.ownerGlobal.OpenBrowserWindow({ aiWindow: true }); + return true; + }, +}; diff --git a/browser/components/aiwindow/ui/moz.build b/browser/components/aiwindow/ui/moz.build @@ -12,6 +12,7 @@ MOZ_SRC_FILES += [ "actors/AIChatContentChild.sys.mjs", "actors/AIChatContentParent.sys.mjs", "modules/AIWindow.sys.mjs", + "modules/AIWindowAccountAuth.sys.mjs", "modules/ChatConstants.sys.mjs", "modules/ChatConversation.sys.mjs", "modules/ChatMessage.sys.mjs", diff --git a/toolkit/components/messaging-system/lib/SpecialMessageActions.sys.mjs b/toolkit/components/messaging-system/lib/SpecialMessageActions.sys.mjs @@ -10,6 +10,9 @@ const lazy = {}; ChromeUtils.defineESModuleGetters(lazy, { AddonManager: "resource://gre/modules/AddonManager.sys.mjs", // eslint-disable-next-line mozilla/no-browser-refs-in-toolkit + AIWindowAccountAuth: + "moz-src:///browser/components/aiwindow/ui/modules/AIWindowAccountAuth.sys.mjs", + // eslint-disable-next-line mozilla/no-browser-refs-in-toolkit CustomizableUI: "moz-src:///browser/components/customizableui/CustomizableUI.sys.mjs", ExperimentAPI: "resource://nimbus/ExperimentAPI.sys.mjs", @@ -749,6 +752,9 @@ export const SpecialMessageActions = { case "FXA_SIGNIN_FLOW": /** @returns {Promise<boolean>} */ return this.fxaSignInFlow(action.data, browser); + case "FXA_AIWINDOW_SIGNIN_FLOW": + /** @returns {Promise<boolean>} */ + return lazy.AIWindowAccountAuth.launchAIWindow(browser); case "OPEN_PROTECTION_PANEL": { let { gProtectionsHandler } = window; gProtectionsHandler.showProtectionsPopup({}); diff --git a/toolkit/components/messaging-system/schemas/SpecialMessageActionSchemas/SpecialMessageActionSchemas.json b/toolkit/components/messaging-system/schemas/SpecialMessageActionSchemas/SpecialMessageActionSchemas.json @@ -799,6 +799,18 @@ "properties": { "type": { "type": "string", + "enum": ["FXA_AIWINDOW_SIGNIN_FLOW"] + } + }, + "required": ["type"], + "additionalProperties": false, + "description": "Opens AI Window after successful authentication with Accounts sign-in flow" + }, + { + "type": "object", + "properties": { + "type": { + "type": "string", "enum": ["CREATE_TASKBAR_TAB"] } }, diff --git a/toolkit/components/messaging-system/schemas/SpecialMessageActionSchemas/index.md b/toolkit/components/messaging-system/schemas/SpecialMessageActionSchemas/index.md @@ -136,6 +136,14 @@ window or tab closed before sign-in could be completed. In messaging surfaces us Encodes some information that the origin was from about:welcome by default. +### `FXA_AIWINDOW_SIGNIN_FLOW` + +Opens a customized AI Window Firefox accounts sign-up or sign-in flow, and redirects user to AI Window after successful authentication. + +Returns a Promise that resolves to `true` if sign-in succeeded, or to `false` if the sign-in +window or tab closed before sign-in could be completed. + +- args: (none) ### `SHOW_MIGRATION_WIZARD` diff --git a/toolkit/components/messaging-system/schemas/SpecialMessageActionSchemas/test/browser/browser.toml b/toolkit/components/messaging-system/schemas/SpecialMessageActionSchemas/test/browser/browser.toml @@ -31,6 +31,8 @@ support-files = [ ["browser_sma_docs.js"] +["browser_sma_fxa_aiwindow_signin_flow.js"] + ["browser_sma_handle_multiaction.js"] ["browser_sma_open_about_page.js"] diff --git a/toolkit/components/messaging-system/schemas/SpecialMessageActionSchemas/test/browser/browser_sma_fxa_aiwindow_signin_flow.js b/toolkit/components/messaging-system/schemas/SpecialMessageActionSchemas/test/browser/browser_sma_fxa_aiwindow_signin_flow.js @@ -0,0 +1,30 @@ +/* Any copyright is dedicated to the Public Domain. + http://creativecommons.org/publicdomain/zero/1.0/ */ + +"use strict"; + +const { AIWindowAccountAuth } = ChromeUtils.importESModule( + "moz-src:///browser/components/aiwindow/ui/modules/AIWindowAccountAuth.sys.mjs" +); + +add_task(async function test_FXA_AIWINDOW_SIGNIN_FLOW() { + let launchAIWindowStub = sinon.stub(AIWindowAccountAuth, "launchAIWindow"); + launchAIWindowStub.resolves(true); + + await SMATestUtils.executeAndValidateAction({ + type: "FXA_AIWINDOW_SIGNIN_FLOW", + }); + + Assert.equal( + launchAIWindowStub.callCount, + 1, + "Should call launchAIWindow once" + ); + + Assert.ok( + launchAIWindowStub.firstCall.args[0], + "Should be called with browser argument" + ); + + launchAIWindowStub.restore(); +});