Skip to content

Commit ed70df7

Browse files
committed
refactor: secure KernalModeTrust.loginService
1 parent e69c2ac commit ed70df7

File tree

6 files changed

+94
-70
lines changed

6 files changed

+94
-70
lines changed

src/services/login-browser.js

Lines changed: 10 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -43,15 +43,14 @@
4343
*/
4444

4545
define(function (require, exports, module) {
46-
const EventDispatcher = require("utils/EventDispatcher"),
47-
PreferencesManager = require("preferences/PreferencesManager"),
46+
require("./login-service"); // after this, loginService will be in KernalModeTrust
47+
const PreferencesManager = require("preferences/PreferencesManager"),
4848
Metrics = require("utils/Metrics"),
4949
Dialogs = require("widgets/Dialogs"),
5050
DefaultDialogs = require("widgets/DefaultDialogs"),
5151
Strings = require("strings"),
5252
StringUtils = require("utils/StringUtils"),
5353
ProfileMenu = require("./profile-menu"),
54-
LoginService = require("./login-service"),
5554
Mustache = require("thirdparty/mustache/mustache"),
5655
browserLoginWaitingTemplate = require("text!./html/browser-login-waiting-dialog.html");
5756

@@ -60,11 +59,7 @@ define(function (require, exports, module) {
6059
// integrated extensions will have access to kernal mode, but not external extensions
6160
throw new Error("Browser Login service should have access to KernalModeTrust. Cannot boot without trust ring");
6261
}
63-
const secureExports = {};
64-
// Only set loginService for browser apps to avoid conflict with desktop login
65-
if (!Phoenix.isNativeApp) {
66-
KernalModeTrust.loginService = secureExports;
67-
}
62+
const LoginService = KernalModeTrust.loginService;
6863

6964
// user profile structure: "customerID": "uuid...", "firstName":"Aa","lastName":"bb",
7065
// "email":"[email protected]", "loginTime":1750074393853, "isSuccess": true,
@@ -75,14 +70,6 @@ define(function (require, exports, module) {
7570
// just used as trigger to notify different windows about user profile changes
7671
const PREF_USER_PROFILE_VERSION = "userProfileVersion";
7772

78-
EventDispatcher.makeEventDispatcher(exports);
79-
EventDispatcher.makeEventDispatcher(secureExports);
80-
81-
const _EVT_PAGE_FOCUSED = "page_focused";
82-
$(window).focus(function () {
83-
exports.trigger(_EVT_PAGE_FOCUSED);
84-
});
85-
8673
function isLoggedIn() {
8774
return isLoggedInUser;
8875
}
@@ -199,7 +186,6 @@ define(function (require, exports, module) {
199186
}
200187

201188
let loginWaitingDialog = null;
202-
let focusCheckInterval = null;
203189

204190
/**
205191
* Show waiting dialog with auto-detection and manual check options
@@ -288,10 +274,6 @@ define(function (require, exports, module) {
288274
loginWaitingDialog.close();
289275
loginWaitingDialog = null;
290276
}
291-
if (focusCheckInterval) {
292-
clearInterval(focusCheckInterval);
293-
focusCheckInterval = null;
294-
}
295277
$(window).off('focus.loginWaiting');
296278
}
297279

@@ -413,14 +395,13 @@ define(function (require, exports, module) {
413395
if (!Phoenix.isNativeApp) {
414396
init();
415397
// kernal exports
416-
secureExports.isLoggedIn = isLoggedIn;
417-
secureExports.signInToAccount = signInToBrowser;
418-
secureExports.signOutAccount = signOutBrowser;
419-
secureExports.getProfile = getProfile;
420-
secureExports.verifyLoginStatus = () => _verifyBrowserLogin(false);
421-
secureExports.getAccountBaseURL = _getAccountBaseURL;
422-
secureExports.getEntitlements = LoginService.getEntitlements;
423-
secureExports.EVENT_ENTITLEMENTS_CHANGED = LoginService.EVENT_ENTITLEMENTS_CHANGED;
398+
// Add to existing KernalModeTrust.loginService from login-service.js
399+
LoginService.isLoggedIn = isLoggedIn;
400+
LoginService.signInToAccount = signInToBrowser;
401+
LoginService.signOutAccount = signOutBrowser;
402+
LoginService.getProfile = getProfile;
403+
LoginService.verifyLoginStatus = () => _verifyBrowserLogin(false);
404+
LoginService.getAccountBaseURL = _getAccountBaseURL;
424405
}
425406

426407
// public exports

src/services/login-desktop.js

Lines changed: 16 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,8 @@
1919
/*global logger*/
2020

2121
define(function (require, exports, module) {
22+
require("./login-service"); // after this, loginService will be in KernalModeTrust
23+
2224
const EventDispatcher = require("utils/EventDispatcher"),
2325
PreferencesManager = require("preferences/PreferencesManager"),
2426
Metrics = require("utils/Metrics"),
@@ -27,7 +29,6 @@ define(function (require, exports, module) {
2729
Strings = require("strings"),
2830
NativeApp = require("utils/NativeApp"),
2931
ProfileMenu = require("./profile-menu"),
30-
LoginService = require("./login-service"),
3132
Mustache = require("thirdparty/mustache/mustache"),
3233
NodeConnector = require("NodeConnector"),
3334
otpDialogTemplate = require("text!./html/otp-dialog.html");
@@ -37,11 +38,8 @@ define(function (require, exports, module) {
3738
// integrated extensions will have access to kernal mode, but not external extensions
3839
throw new Error("Login service should have access to KernalModeTrust. Cannot boot without trust ring");
3940
}
40-
const secureExports = {};
41-
// Only set loginService for native apps to avoid conflict with browser login
42-
if (Phoenix.isNativeApp) {
43-
KernalModeTrust.loginService = secureExports;
44-
}
41+
const LoginService = KernalModeTrust.loginService;
42+
4543
// user profile is something like "apiKey": "uuid...", validationCode: "dfdf", "firstName":"Aa","lastName":"bb",
4644
// "email":"[email protected]", "customerID":"uuid...","loginTime":1750074393853,
4745
// "profileIcon":{"color":"#14b8a6","initials":"AB"}
@@ -51,12 +49,11 @@ define(function (require, exports, module) {
5149
// just used as trigger to notify different windows about user profile changes
5250
const PREF_USER_PROFILE_VERSION = "userProfileVersion";
5351

54-
EventDispatcher.makeEventDispatcher(exports);
55-
EventDispatcher.makeEventDispatcher(secureExports);
56-
5752
const _EVT_PAGE_FOCUSED = "page_focused";
53+
const focusWatcher = {};
54+
EventDispatcher.makeEventDispatcher(focusWatcher);
5855
$(window).focus(function () {
59-
exports.trigger(_EVT_PAGE_FOCUSED);
56+
focusWatcher.trigger(_EVT_PAGE_FOCUSED);
6057
});
6158

6259
const AUTH_CONNECTOR_ID = "ph_auth";
@@ -320,7 +317,7 @@ define(function (require, exports, module) {
320317
}
321318
}
322319
let isAutoSignedIn = false;
323-
exports.on(_EVT_PAGE_FOCUSED, checkLoginStatus);
320+
focusWatcher.on(_EVT_PAGE_FOCUSED, checkLoginStatus);
324321
async function _AutoSignedIn() {
325322
isAutoSignedIn = true;
326323
await checkLoginStatus();
@@ -329,7 +326,7 @@ define(function (require, exports, module) {
329326

330327
// Clean up when dialog is closed
331328
dialog.done(function() {
332-
exports.off(_EVT_PAGE_FOCUSED, checkLoginStatus);
329+
focusWatcher.off(_EVT_PAGE_FOCUSED, checkLoginStatus);
333330
authNodeConnector.off(EVENT_CONNECTED, _AutoSignedIn);
334331
clearTimeout(closeTimeout);
335332
Metrics.countEvent(Metrics.EVENT_TYPE.AUTH,
@@ -411,15 +408,13 @@ define(function (require, exports, module) {
411408
// Only set exports for native apps to avoid conflict with browser login
412409
if (Phoenix.isNativeApp) {
413410
init();
414-
// kernal exports
415-
secureExports.isLoggedIn = isLoggedIn;
416-
secureExports.signInToAccount = signInToAccount;
417-
secureExports.signOutAccount = signOutAccount;
418-
secureExports.getProfile = getProfile;
419-
secureExports.verifyLoginStatus = () => _verifyLogin(false);
420-
secureExports.getAccountBaseURL = getAccountBaseURL;
421-
secureExports.getEntitlements = LoginService.getEntitlements;
422-
secureExports.EVENT_ENTITLEMENTS_CHANGED = LoginService.EVENT_ENTITLEMENTS_CHANGED;
411+
// kernal exports - add to existing KernalModeTrust.loginService from login-service.js
412+
LoginService.isLoggedIn = isLoggedIn;
413+
LoginService.signInToAccount = signInToAccount;
414+
LoginService.signOutAccount = signOutAccount;
415+
LoginService.getProfile = getProfile;
416+
LoginService.verifyLoginStatus = () => _verifyLogin(false);
417+
LoginService.getAccountBaseURL = getAccountBaseURL;
423418
}
424419

425420
// public exports

src/services/login-service.js

Lines changed: 14 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -24,14 +24,17 @@
2424
*/
2525

2626
define(function (require, exports, module) {
27-
const Promotions = require("./promotions");
27+
require("./setup-login-service"); // this adds loginService to KernalModeTrust
28+
require("./promotions");
2829

2930
const KernalModeTrust = window.KernalModeTrust;
3031
if(!KernalModeTrust){
3132
// integrated extensions will have access to kernal mode, but not external extensions
3233
throw new Error("Login service should have access to KernalModeTrust. Cannot boot without trust ring");
3334
}
3435

36+
const LoginService = KernalModeTrust.loginService;
37+
3538
// Event constants
3639
const EVENT_ENTITLEMENTS_CHANGED = "entitlements_changed";
3740

@@ -44,7 +47,7 @@ define(function (require, exports, module) {
4447
*/
4548
async function getEntitlements(forceRefresh = false) {
4649
// Return null if not logged in
47-
if (!KernalModeTrust.loginService.isLoggedIn()) {
50+
if (!LoginService.isLoggedIn()) {
4851
return null;
4952
}
5053

@@ -54,7 +57,7 @@ define(function (require, exports, module) {
5457
}
5558

5659
try {
57-
const accountBaseURL = KernalModeTrust.loginService.getAccountBaseURL();
60+
const accountBaseURL = LoginService.getAccountBaseURL();
5861
const language = Phoenix.app && Phoenix.app.language ? Phoenix.app.language : 'en';
5962
let url = `${accountBaseURL}/getAppEntitlements?lang=${language}`;
6063
let fetchOptions = {
@@ -67,7 +70,7 @@ define(function (require, exports, module) {
6770
// Handle different authentication methods for browser vs desktop
6871
if (Phoenix.isNativeApp) {
6972
// Desktop app: use appSessionID and validationCode
70-
const profile = KernalModeTrust.loginService.getProfile();
73+
const profile = LoginService.getProfile();
7174
if (profile && profile.apiKey && profile.validationCode) {
7275
url += `&appSessionID=${encodeURIComponent(profile.apiKey)}&validationCode=${encodeURIComponent(profile.validationCode)}`;
7376
} else {
@@ -91,7 +94,7 @@ define(function (require, exports, module) {
9194

9295
// Trigger event if entitlements changed
9396
if (entitlementsChanged) {
94-
KernalModeTrust.loginService.trigger(EVENT_ENTITLEMENTS_CHANGED, result);
97+
LoginService.trigger(EVENT_ENTITLEMENTS_CHANGED, result);
9598
}
9699

97100
return cachedEntitlements;
@@ -113,14 +116,14 @@ define(function (require, exports, module) {
113116
cachedEntitlements = null;
114117

115118
// Trigger event when entitlements are cleared
116-
if (KernalModeTrust.loginService.trigger) {
117-
KernalModeTrust.loginService.trigger(EVENT_ENTITLEMENTS_CHANGED, null);
119+
if (LoginService.trigger) {
120+
LoginService.trigger(EVENT_ENTITLEMENTS_CHANGED, null);
118121
}
119122
}
120123
}
121124

122-
// Exports
123-
exports.EVENT_ENTITLEMENTS_CHANGED = EVENT_ENTITLEMENTS_CHANGED;
124-
exports.getEntitlements = getEntitlements;
125-
exports.clearEntitlements = clearEntitlements;
125+
// Add functions to secure exports
126+
LoginService.getEntitlements = getEntitlements;
127+
LoginService.clearEntitlements = clearEntitlements;
128+
LoginService.EVENT_ENTITLEMENTS_CHANGED = EVENT_ENTITLEMENTS_CHANGED;
126129
});

src/services/profile-menu.js

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -539,7 +539,7 @@ define(function (require, exports, module) {
539539
_removeProfileIcon();
540540

541541
// Clear cached entitlements when user logs out
542-
LoginService.clearEntitlements();
542+
KernalModeTrust.loginService.clearEntitlements();
543543

544544
// Reset branding to free mode
545545
_updateBranding(null);
@@ -563,4 +563,6 @@ define(function (require, exports, module) {
563563
exports.init = init;
564564
exports.setNotLoggedIn = setNotLoggedIn;
565565
exports.setLoggedIn = setLoggedIn;
566+
567+
// dont public exports things that extensions can use to get/put credentials and entitlements, display mods is fine
566568
});

src/services/promotions.js

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -31,17 +31,16 @@
3131

3232
define(function (require, exports, module) {
3333

34-
const EventDispatcher = require("utils/EventDispatcher"),
35-
Metrics = require("utils/Metrics"),
34+
require("./setup-login-service"); // this adds loginService to KernalModeTrust
35+
const Metrics = require("utils/Metrics"),
3636
semver = require("thirdparty/semver.browser");
3737

3838
const KernalModeTrust = window.KernalModeTrust;
3939
if (!KernalModeTrust) {
4040
throw new Error("Promotions service requires access to KernalModeTrust. Cannot boot without trust ring");
4141
}
4242

43-
// Make this module an event dispatcher
44-
EventDispatcher.makeEventDispatcher(exports);
43+
const LoginService = KernalModeTrust.loginService;
4544

4645
// Constants
4746
const EVENT_PRO_UPGRADE_ON_INSTALL = "pro_upgrade_on_install";
@@ -244,7 +243,7 @@ define(function (require, exports, module) {
244243
console.log(`Pro trial activated for ${trialDays} days`);
245244

246245
// Trigger the event for UI to handle
247-
exports.trigger(EVENT_PRO_UPGRADE_ON_INSTALL, {
246+
LoginService.trigger(EVENT_PRO_UPGRADE_ON_INSTALL, {
248247
trialDays: trialDays,
249248
isFirstInstall: !existingTrialData
250249
});
@@ -273,8 +272,9 @@ define(function (require, exports, module) {
273272
});
274273
}, TRIAL_POLL_MS);
275274

276-
// Public exports
277-
exports.isProTrialActivated = isProTrialActivated;
278-
exports.EVENT_PRO_UPGRADE_ON_INSTALL = EVENT_PRO_UPGRADE_ON_INSTALL;
275+
// Add to secure exports
276+
LoginService.isProTrialActivated = isProTrialActivated;
277+
LoginService.EVENT_PRO_UPGRADE_ON_INSTALL = EVENT_PRO_UPGRADE_ON_INSTALL;
279278

279+
// no public exports to prevent extension tampering
280280
});
Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
/*
2+
* GNU AGPL-3.0 License
3+
*
4+
* Copyright (c) 2021 - present core.ai . All rights reserved.
5+
*
6+
* This program is free software: you can redistribute it and/or modify it under
7+
* the terms of the GNU Affero General Public License as published by the Free
8+
* Software Foundation, either version 3 of the License, or (at your option) any later version.
9+
*
10+
* This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
11+
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
12+
* See the GNU Affero General Public License for more details.
13+
*
14+
* You should have received a copy of the GNU Affero General Public License
15+
* along with this program. If not, see https://opensource.org/licenses/AGPL-3.0.
16+
*
17+
*/
18+
19+
/**
20+
* Shared Login Service kernal mode trust setup
21+
*
22+
* This module contains shared login service functionality used by both
23+
* browser and desktop login implementations, including entitlements management.
24+
*/
25+
26+
define(function (require, exports, module) {
27+
const EventDispatcher = require("utils/EventDispatcher");
28+
29+
const KernalModeTrust = window.KernalModeTrust;
30+
if(!KernalModeTrust){
31+
// integrated extensions will have access to kernal mode, but not external extensions
32+
throw new Error("Login service should have access to KernalModeTrust. Cannot boot without trust ring");
33+
}
34+
35+
// Create secure exports and set up KernalModeTrust.loginService
36+
const secureExports = {};
37+
EventDispatcher.makeEventDispatcher(secureExports);
38+
39+
// Set up loginService for both native and browser apps
40+
KernalModeTrust.loginService = secureExports;
41+
42+
// no public exports to prevent extension tampering
43+
});

0 commit comments

Comments
 (0)