Skip to content

Commit 80f159e

Browse files
authored
Merge pull request #277 from mozilla/enable-sync
FxA and Sync Support
2 parents 33ecf56 + b9b9f0a commit 80f159e

File tree

22 files changed

+553
-15
lines changed

22 files changed

+553
-15
lines changed

.github/workflows/enterprise.yml

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -260,6 +260,11 @@ jobs:
260260
. venv_tests/bin/activate
261261
MOZ_LOG=console:5 xvfb-run python3 test_felt_browser_external_link.py ${{ steps.unpack.outputs.runtime_path }} $PWD/geckodriver $PWD/profiles/
262262
263+
- name: "test browser fxa"
264+
run: |
265+
. venv_tests/bin/activate
266+
MOZ_LOG=console:5 python3 test_felt_browser_fxa.py ${{ steps.unpack.outputs.runtime_path }} $PWD/geckodriver $PWD/profiles/
267+
263268
- name: "test browser restart is a quit"
264269
run: |
265270
. venv_tests/bin/activate
@@ -543,6 +548,12 @@ jobs:
543548
$Env:MOZ_LOG="console:5"
544549
python3 test_felt_browser_signout.py "${{ steps.unpack.outputs.firefox_path }}" "${{ steps.unpack.outputs.geckodriver_path }}" "${{ steps.unpack.outputs.profiles_path }}"
545550
551+
- name: "test browser fxa"
552+
run: |
553+
. venv_tests\Scripts\activate
554+
$Env:MOZ_LOG="console:5"
555+
python3 test_felt_browser_fxa.py "${{ steps.unpack.outputs.firefox_path }}" "${{ steps.unpack.outputs.geckodriver_path }}" "${{ steps.unpack.outputs.profiles_path }}"
556+
546557
### This is failing on our GCP workers in a non debuggable way.
547558
### GitHub Actions Windows workers are fine and TaskCluster.
548559
# - name: "test browser safe mode"
@@ -977,6 +988,11 @@ jobs:
977988
. venv_tests/bin/activate
978989
MOZ_LOG=console:5 python3 test_felt_browser_signout.py "${{ steps.attach.outputs.runtime_path }}" $PWD/geckodriver $PWD/profiles/
979990
991+
- name: "test browser fxa"
992+
run: |
993+
. venv_tests/bin/activate
994+
MOZ_LOG=console:5 python3 test_felt_browser_fxa.py "${{ steps.attach.outputs.runtime_path }}" $PWD/geckodriver $PWD/profiles/
995+
980996
- name: "test browser safe mode"
981997
run: |
982998
. venv_tests/bin/activate

.prettierignore

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1241,6 +1241,8 @@ toolkit/modules/AppConstants.sys.mjs
12411241

12421242
# Files with MOZ_ENTERPRISE preprocessor directives
12431243
browser/components/enterprisepolicies/helpers/WebsiteFilter.sys.mjs
1244+
services/fxaccounts/FxAccounts.sys.mjs
1245+
services/fxaccounts/FxAccountsClient.sys.mjs
12441246
toolkit/components/downloads/DownloadCore.sys.mjs
12451247
toolkit/components/printing/content/print.js
12461248
toolkit/mozapps/extensions/AddonManager.sys.mjs

browser/branding/enterprise/pref/firefox-enterprise.js

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,15 @@
44

55
/* global pref */
66

7-
// This file contains felt-specific prefs.
87
pref("enterprise.console.address", "https://console.enterfox.eu");
8+
9+
// Endpoint will be provided by the console.
10+
pref(
11+
"identity.sync.tokenserver.uri",
12+
"https://ent-dev-tokenserver.sync.nonprod.webservices.mozgcp.net/1.0/sync/1.5"
13+
);
14+
915
pref("browser.profiles.enabled", false);
1016
pref("extensions.activeThemeID", "firefox-enterprise-light@mozilla.org");
17+
18+
pref("enterprise.loglevel", "Error");

browser/components/BrowserComponents.manifest

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -108,5 +108,8 @@ category browser-quit-application-granted resource://gre/modules/UpdateListener.
108108
#endif
109109
category browser-quit-application-granted moz-src:///browser/components/urlbar/UrlbarSearchTermsPersistence.sys.mjs UrlbarSearchTermsPersistence.uninit
110110
category browser-quit-application-granted resource:///modules/ipprotection/IPProtectionService.sys.mjs IPProtectionService.uninit
111+
#ifdef MOZ_ENTERPRISE
112+
category browser-quit-application-granted resource:///modules/enterprise/EnterpriseHandler.sys.mjs EnterpriseHandler.uninit
113+
#endif
111114

112115
category search-service-notification moz-src:///browser/components/search/SearchUIUtils.sys.mjs SearchUIUtils.showSearchServiceNotification

browser/components/enterprise/EnterpriseCommon.sys.mjs

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,4 +8,7 @@ export const isTesting = () => {
88
return Services.prefs.getBoolPref(IS_TESTING_ENVIRONMENT, false);
99
};
1010

11-
export const EnterpriseCommon = {};
11+
export const EnterpriseCommon = {
12+
ENTERPRISE_DEVICE_ID_PREF: "enterprise.sync.device_id",
13+
ENTERPRISE_LOGLEVEL_PREF: "enterprise.loglevel",
14+
};

browser/components/enterprise/EnterpriseHandler.sys.mjs

Lines changed: 122 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -11,21 +11,119 @@ ChromeUtils.defineLazyGetter(lazy, "localization", () => {
1111
ChromeUtils.defineESModuleGetters(lazy, {
1212
BrowserUtils: "resource://gre/modules/BrowserUtils.sys.mjs",
1313
ConsoleClient: "resource:///modules/enterprise/ConsoleClient.sys.mjs",
14+
EnterpriseCommon: "resource:///modules/enterprise/EnterpriseCommon.sys.mjs",
15+
UIState: "resource://services-sync/UIState.sys.mjs",
16+
Weave: "resource://services-sync/main.sys.mjs",
17+
});
18+
19+
ChromeUtils.defineLazyGetter(lazy, "log", () => {
20+
return console.createInstance({
21+
prefix: "EnterpriseHandler",
22+
maxLogLevelPref: lazy.EnterpriseCommon.ENTERPRISE_LOGLEVEL_PREF,
23+
});
1424
});
1525

1626
const PROMPT_ON_SIGNOUT_PREF = "enterprise.promptOnSignout";
27+
const ENTERPRISE_SYNC_ENABLED_PREF = "enterprise.sync.enabledByDefault";
1728

1829
export const EnterpriseHandler = {
1930
/**
2031
* @type {{name:string, email:string, pictureUrl:string} | null}
2132
*/
2233
_signedInUser: null,
2334

24-
async init(window) {
25-
await this.initUser();
35+
/**
36+
* Whether the handler is initialized, hence we have retrieved the
37+
* user information and initialized the sync state.
38+
*/
39+
_isInitialized: false,
2640

27-
this.hideFxaToolbarButton(window);
41+
/**
42+
* Handles the enterprise state for each new browser window.
43+
* On first call:
44+
* - Make a request to the console to retrieve the user information of the signed in user.
45+
* - Configure sync to be enabled or disable (depending on ENTERPRISE_SYNC_ENABLED_PREF)
46+
* On every call:
47+
* - Hide FxA toolbar button and FxA item in app menu (hamburger menu)
48+
*
49+
* @param {Window} window chrome window
50+
*/
51+
async init(window) {
52+
if (!this._isInitialized) {
53+
lazy.log.debug("Initializing...");
54+
await this.initUser();
55+
this.setupSyncOnceInitialized(window);
56+
}
2857
this.updateBadge(window);
58+
this.restrictEnterpriseView(window);
59+
this._isInitialized = true;
60+
},
61+
62+
/**
63+
* Check if the FxA state is initialised yet.
64+
* - If the state is still undefined, listen for a state update
65+
* and set up once the state update occurs.
66+
* - If the state is initialized, set up sync immediately.
67+
*
68+
* @param {Window} window chrome window
69+
*/
70+
setupSyncOnceInitialized(window) {
71+
const status = lazy.UIState.get().status;
72+
if (status === lazy.UIState.get().STATUS_NOT_CONFIGURED) {
73+
// State not configured yet.
74+
lazy.log.debug("Waiting for FxA/Sync status to be updated");
75+
const syncStateObserver = (_, topic) => {
76+
switch (topic) {
77+
case lazy.UIState.ON_UPDATE:
78+
lazy.log.debug("Sync state has been initialized");
79+
this.setUpSync(window);
80+
Services.obs.removeObserver(
81+
syncStateObserver,
82+
lazy.UIState.ON_UPDATE
83+
);
84+
break;
85+
default:
86+
break;
87+
}
88+
};
89+
Services.obs.addObserver(syncStateObserver, lazy.UIState.ON_UPDATE);
90+
return;
91+
}
92+
this.setUpSync();
93+
},
94+
95+
/**
96+
* Align sync state with expected state (ENTERPRISE_SYNC_ENABLED_PREF)
97+
* by enabling or disabling sync.
98+
*
99+
* @param {Window} window chrome window
100+
*/
101+
setUpSync(window) {
102+
lazy.log.debug("Handling sync state.");
103+
const isSyncCurrentlyEnabled = lazy.UIState.get().syncEnabled;
104+
const isEnableSync = Services.prefs.getBoolPref(
105+
ENTERPRISE_SYNC_ENABLED_PREF,
106+
false
107+
);
108+
109+
if (isSyncCurrentlyEnabled === isEnableSync) {
110+
// Nothing to do
111+
lazy.log.debug(
112+
`Not changing sync state. It was already ${isSyncCurrentlyEnabled ? "enabled" : "disabled"}`
113+
);
114+
return;
115+
}
116+
117+
if (isEnableSync) {
118+
lazy.log.debug(`Connect sync.`);
119+
lazy.Weave.Service.configure();
120+
} else {
121+
lazy.log.debug(`Disconnect sync.`);
122+
window.gSync.disconnect({
123+
confirm: false,
124+
disconnectAccount: false,
125+
});
126+
}
29127
},
30128

31129
async initUser() {
@@ -42,6 +140,11 @@ export const EnterpriseHandler = {
42140
}
43141
},
44142

143+
/**
144+
* Updates the user icon
145+
*
146+
* @param {Window} window chrome window
147+
*/
45148
updateBadge(window) {
46149
const userIcon = window.document.querySelector("#enterprise-user-icon");
47150

@@ -99,11 +202,17 @@ export const EnterpriseHandler = {
99202
}
100203
},
101204

102-
// TODO: FxA shows up in a lot of different areas. For now we hide the most prominent
103-
// toolbar button. How to hide or integrate with Fxa and Sync to be determined.
104-
hideFxaToolbarButton(window) {
105-
const fxaBtn = window.document.getElementById("fxa-toolbar-menu-button");
106-
fxaBtn.hidden = true;
205+
/**
206+
* Hide away FxA appearances in the toolbar and the app menu (hamburger menu)
207+
*
208+
* @param {Window} window chrome window
209+
*/
210+
restrictEnterpriseView(window) {
211+
// Hides fxa toolbar button
212+
Services.prefs.setBoolPref("identity.fxaccounts.toolbar.enabled", false);
213+
214+
// Hides fxa item and separator in main view (hamburg menu)
215+
window.PanelUI.mainView.setAttribute("restricted-enterprise-view", true);
107216
},
108217

109218
async onSignOut(window) {
@@ -168,4 +277,9 @@ export const EnterpriseHandler = {
168277
Services.startup.quit(Ci.nsIAppStartup.eForceQuit);
169278
}
170279
},
280+
281+
uninit() {
282+
this._signedInUser = {};
283+
this._isInitialized = false;
284+
},
171285
};

browser/components/enterprise/modules/ConsoleClient.sys.mjs

Lines changed: 51 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ const lazy = {};
66

77
ChromeUtils.defineESModuleGetters(lazy, {
88
TelemetryEnvironment: "resource://gre/modules/TelemetryEnvironment.sys.mjs",
9+
EnterpriseCommon: "resource:///modules/enterprise/EnterpriseCommon.sys.mjs",
910
});
1011

1112
/**
@@ -104,6 +105,10 @@ export const ConsoleClient = {
104105
DEVICE_POSTURE: "/sso/device_posture",
105106
WHOAMI: "/api/browser/whoami",
106107
LEARN_MORE: "/downloads/firefox.html",
108+
FXACCOUNT: "/api/browser/account",
109+
FXACCOUNTS_OAUTH: "/api/fxa/oauth/v1",
110+
FXACCOUNTS_PROFILE: "/api/fxa/profile/v1",
111+
FXACCOUNTS_AUTH: "/api/fxa/api/v1",
107112
};
108113
},
109114

@@ -148,6 +153,33 @@ export const ConsoleClient = {
148153
return url.href;
149154
},
150155

156+
/**
157+
* Get the FxAccounts OAuth endpoint of the console
158+
*
159+
* returns {string} URI of the endpoint
160+
*/
161+
get fxAccountsOAuth() {
162+
return this.constructURI(this._paths.FXACCOUNTS_OAUTH);
163+
},
164+
165+
/**
166+
* Get the FxAccounts Profile endpoint of the console
167+
*
168+
* returns {string} URI of the endpoint
169+
*/
170+
get fxAccountsProfile() {
171+
return this.constructURI(this._paths.FXACCOUNTS_PROFILE);
172+
},
173+
174+
/**
175+
* Get the FxAccounts Auth endpoint of the console
176+
*
177+
* returns {string} URI of the endpoint
178+
*/
179+
get fxAccountsAuth() {
180+
return this.constructURI(this._paths.FXACCOUNTS_AUTH);
181+
},
182+
151183
/**
152184
* SSO callback uri that we match to create Felt actors on
153185
*
@@ -189,6 +221,24 @@ export const ConsoleClient = {
189221
return payload;
190222
},
191223

224+
/**
225+
* Fetch the account data used for fxa and sync.
226+
*
227+
* @returns {Promise<object>}
228+
*/
229+
async getFxAccountData() {
230+
const deviceId = Services.prefs.getStringPref(
231+
lazy.EnterpriseCommon.ENTERPRISE_DEVICE_ID_PREF,
232+
""
233+
);
234+
const body = {};
235+
if (deviceId !== "") {
236+
body.device_id = deviceId;
237+
}
238+
const payload = await this._post(this._paths.FXACCOUNT, body);
239+
return payload;
240+
},
241+
192242
/**
193243
* Collect the device posture data and send them to the console.
194244
*
@@ -506,4 +556,4 @@ export const ConsoleClient = {
506556
}
507557
}
508558
},
509-
}.init();
559+
}.init();

0 commit comments

Comments
 (0)