Skip to content

Commit 7fbbc7a

Browse files
author
Alexandre Lissy
committed
FELT: Signout
1 parent 5c14d33 commit 7fbbc7a

File tree

11 files changed

+299
-24
lines changed

11 files changed

+299
-24
lines changed

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

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -213,10 +213,12 @@ export const ConsoleClient = {
213213
get _paths() {
214214
return {
215215
SSO: "/sso/login",
216+
SIGNOUT: "/sso/logout",
216217
SSO_CALLBACK: "/sso/callback",
217218
STARTUP_PREFS: "/api/browser/hacks/startup",
218219
DEFAULT_PREFS: "/api/browser/hacks/default",
219220
REMOTE_POLICIES: "/api/browser/policies",
221+
WHOAMI: "/api/browser/whoami",
220222
TOKEN: "/sso/token",
221223
DEVICE_POSTURE: "/sso/device_posture",
222224
};
@@ -517,6 +519,53 @@ export const ConsoleClient = {
517519
Services.prefs.clearUserPref(PREFS.REFRESH_TOKEN);
518520
},
519521

522+
/**
523+
* Perform signout against the console and share the information down to
524+
* XPCOM to make FELT aware.
525+
*
526+
* This is expected to be executed from the browser side.
527+
*/
528+
async signout() {
529+
console.debug(`FeltConsoleClient: signout`);
530+
if (!Services.felt.isFeltBrowser()) {
531+
throw new Error(
532+
"Performing signout from something else than browser is wrong"
533+
);
534+
}
535+
536+
// TODO: Assert or force-enable session restore?
537+
538+
// Notify FELT that we are logging out so the shutdown is a normal one
539+
// that should not be followed by restarting the process.
540+
Services.felt.performSignout();
541+
542+
const headers = new Headers({});
543+
const { tokenType, accessToken } = this.tokenData;
544+
headers.set("Authorization", `${tokenType} ${accessToken}`);
545+
headers.set("Content-Type", "application/json");
546+
headers.set("Accept", "application/json");
547+
548+
this.clearTokenData();
549+
550+
const url = this.constructURI(this._paths.SIGNOUT);
551+
const res = await fetch(url, {
552+
method: "POST",
553+
headers,
554+
});
555+
556+
if (res.ok) {
557+
console.debug(`FeltConsoleClient: quit(eForceQuit)`);
558+
Services.startup.quit(Ci.nsIAppStartup.eForceQuit);
559+
return;
560+
}
561+
562+
const text = await res.text().catch(() => "");
563+
console.debug(
564+
`FeltConsoleClient: signout failure ${res.status} => ${text}`
565+
);
566+
throw new Error(`Post failed (${res.status}): ${text}`);
567+
},
568+
520569
/**
521570
* Register shutdown observer to clean up the client.
522571
*/

browser/extensions/felt/api.js

Lines changed: 19 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -53,10 +53,12 @@ this.felt = class extends ExtensionAPI {
5353

5454
onStartup() {
5555
if (Services.felt.isFeltUI()) {
56+
this._ignoreNextNormalExit = false;
5657
this.registerChrome();
5758
this.registerActors();
5859
this.showWindow();
5960
Services.ppmm.addMessageListener("FeltParent:FirefoxNormalExit", this);
61+
Services.ppmm.addMessageListener("FeltParent:FirefoxLogoutExit", this);
6062
Services.ppmm.addMessageListener("FeltParent:FirefoxAbnormalExit", this);
6163
Services.ppmm.addMessageListener("FeltParent:FirefoxStarting", this);
6264
}
@@ -65,7 +67,13 @@ this.felt = class extends ExtensionAPI {
6567
receiveMessage(message) {
6668
console.debug(`FeltExtension: ${message.name} handling ...`);
6769
switch (message.name) {
68-
case "FeltParent:FirefoxNormalExit":
70+
case "FeltParent:FirefoxNormalExit": {
71+
if (this._ignoreNextNormalExit) {
72+
this._ignoreNextNormalExit = false;
73+
console.debug(`FeltExtension: ${message.name} ignored ...`);
74+
return;
75+
}
76+
6977
Services.ppmm.removeMessageListener(
7078
"FeltParent:FirefoxNormalExit",
7179
this
@@ -74,6 +82,7 @@ this.felt = class extends ExtensionAPI {
7482
Ci.nsIAppStartup.eAttemptQuit | Ci.nsIAppStartup.eConsiderQuit
7583
);
7684
break;
85+
}
7786

7887
case "FeltParent:FirefoxAbnormalExit":
7988
Services.ppmm.removeMessageListener(
@@ -83,11 +92,19 @@ this.felt = class extends ExtensionAPI {
8392
// TODO: What should we do, restart Firefox?
8493
break;
8594

95+
case "FeltParent:FirefoxLogoutExit": {
96+
this._ignoreNextNormalExit = true;
97+
const success = Services.felt.makeBackgroundProcess(false);
98+
console.debug(`FeltExtension: makeBackgroundProcess? ${success}`);
99+
this.showWindow();
100+
break;
101+
}
102+
86103
case "FeltParent:FirefoxStarting": {
87104
Services.startup.enterLastWindowClosingSurvivalArea();
88105
Services.ww.unregisterNotification(this.windowObserver);
89106
this._win.close();
90-
const success = Services.felt.makeBackgroundProcess();
107+
const success = Services.felt.makeBackgroundProcess(true);
91108
console.debug(`FeltExtension: makeBackgroundProcess? ${success}`);
92109
break;
93110
}

browser/extensions/felt/content/FeltProcessParent.sys.mjs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,11 @@ export class FeltProcessParent extends JSProcessActorParent {
4545
}
4646
break;
4747
}
48+
49+
case "felt-firefox-logout":
50+
Services.cpmm.sendAsyncMessage("FeltParent:FirefoxLogoutExit", {});
51+
break;
52+
4853
default:
4954
console.debug(`FeltExtension: ParentProcess: Unhandled ${aTopic}`);
5055
break;
@@ -54,6 +59,7 @@ export class FeltProcessParent extends JSProcessActorParent {
5459

5560
Services.cpmm.addMessageListener("FeltParent:RestartFirefox", this);
5661
Services.obs.addObserver(this.restartObserver, "felt-firefox-restarting");
62+
Services.obs.addObserver(this.restartObserver, "felt-firefox-logout");
5763
}
5864

5965
sanitizePrefs(prefs) {

browser/extensions/felt/content/window.js

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -92,11 +92,13 @@ function listenFormEmailSubmission() {
9292
function setupMarionetteEnvironment() {
9393
window.gBrowser = {
9494
get selectedBrowser() {
95+
console.debug(`FeltExtension: get selectedBrowser()`);
9596
let rv = document.getElementById("browser");
9697
return rv;
9798
},
9899

99100
get tabs() {
101+
console.debug(`FeltExtension: get tabs()`);
100102
let ts = [
101103
{
102104
linkedBrowser: this.selectedBrowser,
@@ -106,10 +108,12 @@ function setupMarionetteEnvironment() {
106108
},
107109

108110
get selectedTab() {
111+
console.debug(`FeltExtension: get selectedTab()`);
109112
return this.tabs[0];
110113
},
111114

112115
set selectedTab(tab) {
116+
console.debug(`FeltExtension: set selectedTab()`);
113117
// Synthesize a custom TabSelect event to indicate that a tab has been
114118
// selected even when we don't change it.
115119
const event = new window.CustomEvent("TabSelect", {
@@ -124,18 +128,22 @@ function setupMarionetteEnvironment() {
124128
},
125129

126130
getTabForBrowser() {
131+
console.debug(`FeltExtension: getTabForBrowser()`);
127132
return window;
128133
},
129134

130135
addEventListener() {
136+
console.debug(`FeltExtension: addEventListener()`);
131137
this.selectedBrowser.addEventListener(...arguments);
132138
},
133139

134140
removeEventListener() {
141+
console.debug(`FeltExtension: removeEventListener()`);
135142
this.selectedBrowser.removeEventListener(...arguments);
136143
},
137144
};
138145

146+
console.debug(`FeltExtension: setupMarionetteEnvironment()`);
139147
// Last notification required for marionette to work
140148
Services.obs.notifyObservers(window, "browser-idle-startup-tasks-finished");
141149
}

browser/extensions/felt/rust/nsIFelt.idl

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ interface nsIFelt : nsISupports {
1515
ACString binPath();
1616

1717
[must_use]
18-
boolean makeBackgroundProcess();
18+
boolean makeBackgroundProcess(in boolean background);
1919

2020
[must_use]
2121
boolean isFeltUI();
@@ -43,4 +43,7 @@ interface nsIFelt : nsISupports {
4343

4444
[must_use]
4545
void sendRestartForced();
46+
47+
[must_use]
48+
void performSignout();
4649
};

browser/extensions/felt/rust/src/client.rs

Lines changed: 36 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -79,6 +79,17 @@ impl FeltIpcClient {
7979
}
8080
}
8181

82+
pub fn notify_signout(&self) {
83+
trace!("FeltIpcClient::notify_signout()");
84+
let msg = FeltMessage::LogoutShutdown;
85+
if let Some(tx) = &self.tx {
86+
match tx.send(msg) {
87+
Ok(()) => trace!("FeltIpcClient::notify_signout() SENT"),
88+
Err(err) => trace!("FeltIpcClient::notify_signout() TX ERROR: {}", err),
89+
}
90+
}
91+
}
92+
8293
pub fn report_version(&self) -> bool {
8394
trace!("FeltIpcClient::report_version()");
8495
let msg = FeltMessage::VersionProbe(FELT_IPC_VERSION);
@@ -262,19 +273,34 @@ impl FeltClientThread {
262273
let profile_ready_internal = profile_ready.clone();
263274
let thread_stop_internal = thread_stop.clone();
264275
let notify_restart_internal = notify_restart.clone();
265-
let mut felt_client = self.ipc_client.take();
276+
277+
// Clone the tx: one for the background thread to signal existing,
278+
// one for us to immediately notify Felt is ready (to receive URLs etc),
279+
// this works because ipc-channel::ipc::IpcSender is Send + Sync.
280+
// Take the rx, only needed in the receive thread (and it's not Sync).
281+
let mut client = self.ipc_client.borrow_mut();
282+
let tx_for_thread = client.tx.clone();
283+
let rx_for_thread = client.rx.take();
284+
drop(client);
285+
286+
// Reconstruct a client instance for the thread to send stuff
287+
let thread_client = FeltIpcClient {
288+
tx: tx_for_thread,
289+
rx: rx_for_thread,
290+
};
291+
266292
trace!("FeltClientThread::start_thread(): started thread: build runnable");
267293
let _ = moz_task::RunnableBuilder::new("felt_client::ipc_loop", move || {
268294
trace!("FeltClientThread::start_thread(): felt_client thread runnable");
269295
trace!("FeltClientThread::start_thread(): felt_client version OK");
270-
if let Some(rx) = felt_client.rx.take() {
296+
if let Some(rx) = thread_client.rx.as_ref() {
271297
let mut pending_cookies: Vec<String> = Vec::new();
272298

273299
loop {
274300
if notify_restart_internal.load(Ordering::Relaxed) {
275301
notify_restart_internal.store(false, Ordering::Relaxed);
276302
trace!("FeltClientThread::felt_client::ipc_loop(): restart notification required!");
277-
felt_client.notify_restart();
303+
thread_client.notify_restart();
278304
}
279305

280306
if pending_cookies.len() > 0 && profile_ready_internal.load(Ordering::Relaxed) {
@@ -355,4 +381,11 @@ impl FeltClientThread {
355381
// Wait for the thread to start up.
356382
self.startup_ready.load(Ordering::Acquire)
357383
}
384+
385+
pub fn notify_signout(&self) {
386+
trace!("FeltClientThread::notify_signout()");
387+
let client = self.ipc_client.borrow();
388+
client.notify_signout();
389+
}
390+
358391
}

browser/extensions/felt/rust/src/components.rs

Lines changed: 32 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -106,6 +106,22 @@ impl FeltXPCOM {
106106
self.send(FeltMessage::RestartForced)
107107
}
108108

109+
// Firefox to FELT to notify of logout
110+
fn PerformSignout(&self) -> nserror::nsresult {
111+
trace!("FeltXPCOM::PerformSignout");
112+
let guard = crate::FELT_CLIENT.lock().expect("Could not get lock");
113+
match &*guard {
114+
Some(client) => {
115+
trace!("firefox_felt_send_extension_ready(): sending message");
116+
client.notify_signout();
117+
}
118+
None => {
119+
trace!("firefox_felt_send_extension_ready(): missing client");
120+
}
121+
}
122+
NS_OK
123+
}
124+
109125
fn IpcChannel(&self) -> nserror::nsresult {
110126
let felt_server = match self.one_shot_server.take() {
111127
Some(f) => f,
@@ -181,6 +197,10 @@ impl FeltXPCOM {
181197
trace!("FeltServerThread::felt_server::ipc_loop(): Restarting");
182198
crate::utils::notify_observers("felt-firefox-restarting".to_string());
183199
},
200+
Ok(FeltMessage::LogoutShutdown) => {
201+
trace!("FeltServerThread::felt_server::ipc_loop(): Shutdown for logout");
202+
crate::utils::notify_observers("felt-firefox-logout".to_string());
203+
},
184204
Ok(msg) => {
185205
trace!("FeltServerThread::felt_server::ipc_loop(): UNEXPECTED MSG {:?}", msg);
186206
},
@@ -230,7 +250,7 @@ impl FeltXPCOM {
230250
}
231251
}
232252

233-
fn MakeBackgroundProcess(&self, success: *mut bool) -> nserror::nsresult {
253+
fn MakeBackgroundProcess(&self, background: bool, success: *mut bool) -> nserror::nsresult {
234254
trace!("FeltXPCOM: MakeBackgroundProcess");
235255
unsafe {
236256
*success = false;
@@ -244,6 +264,7 @@ impl FeltXPCOM {
244264
}
245265

246266
type ProcessApplicationTransformState = u32;
267+
let kProcessTransformToForegroundApplication = 1;
247268
let kProcessTransformToBackgroundApplication = 2;
248269
let kCurrentProcess = 2;
249270

@@ -258,8 +279,16 @@ impl FeltXPCOM {
258279
highLongOfPSN: 0,
259280
lowLongOfPSN: kCurrentProcess,
260281
};
261-
let rv =
262-
unsafe { TransformProcessType(&psn, kProcessTransformToBackgroundApplication) };
282+
let rv = unsafe {
283+
TransformProcessType(
284+
&psn,
285+
if background {
286+
kProcessTransformToBackgroundApplication
287+
} else {
288+
kProcessTransformToForegroundApplication
289+
},
290+
)
291+
};
263292
trace!("FeltXPCOM: MakeBackgroundProcess: rv={:?}", rv);
264293

265294
unsafe {

browser/extensions/felt/rust/src/message.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ pub enum FeltMessage {
1616
StartupReady,
1717
RestartForced,
1818
Restarting,
19+
LogoutShutdown,
1920
}
2021

21-
pub const FELT_IPC_VERSION: u32 = 1;
22+
pub const FELT_IPC_VERSION: u32 = 2;
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
{
2+
"test_felt_00_chrome_on_email_submit": {},
3+
"test_felt_0_load_sso": {
4+
"elements": [
5+
["#login", "login"],
6+
["#password", "password"]
7+
]
8+
},
9+
"test_felt_1_perform_sso_auth": {},
10+
"test_felt_3_connect": {},
11+
"test_felt_4_perform_signout": {},
12+
"test_felt_5_whoami": {},
13+
"test_felt_6_browser_exited_show_sso": {}
14+
}

0 commit comments

Comments
 (0)