diff --git a/serve-proxy.js b/serve-proxy.js
index 8c3d236e54..4773be090f 100644
--- a/serve-proxy.js
+++ b/serve-proxy.js
@@ -2,15 +2,14 @@
/* eslint-env node */
const http = require('http');
-const https = require('https');
const url = require('url');
const path = require('path');
const fs = require('fs');
const httpProxy = require('http-proxy');
// Account server configuration - switch between local and production
-const ACCOUNT_SERVER = 'https://account.phcode.dev'; // Production
-// const ACCOUNT_SERVER = 'http://localhost:5000'; // Local development
+//const ACCOUNT_SERVER = 'https://account.phcode.dev'; // Production
+const ACCOUNT_SERVER = 'http://localhost:5000'; // Local development
// Default configuration
let config = {
@@ -90,8 +89,6 @@ proxy.on('proxyReq', (proxyReq, req) => {
if (originalOrigin && originalOrigin.includes('localhost:8000')) {
const newOrigin = originalOrigin.replace(/localhost:8000/g, 'phcode.dev');
proxyReq.setHeader('Origin', newOrigin);
- } else if (!originalOrigin) {
- proxyReq.setHeader('Origin', 'https://phcode.dev');
}
// Ensure HTTPS scheme
diff --git a/src/services/html/profile-popup.html b/src/services/html/profile-popup.html
index a2f5d79144..29f906483a 100644
--- a/src/services/html/profile-popup.html
+++ b/src/services/html/profile-popup.html
@@ -4,9 +4,10 @@
{{initials}}
-
diff --git a/src/services/login-browser.js b/src/services/login-browser.js
index 336984f016..1c139b340d 100644
--- a/src/services/login-browser.js
+++ b/src/services/login-browser.js
@@ -413,6 +413,7 @@ define(function (require, exports, module) {
secureExports.signOutAccount = signOutBrowser;
secureExports.getProfile = getProfile;
secureExports.verifyLoginStatus = () => _verifyBrowserLogin(false);
+ secureExports.getAccountBaseURL = _getAccountBaseURL;
}
// public exports
diff --git a/src/services/login-desktop.js b/src/services/login-desktop.js
index 4dfef4ee5a..b960d369d3 100644
--- a/src/services/login-desktop.js
+++ b/src/services/login-desktop.js
@@ -74,6 +74,14 @@ define(function (require, exports, module) {
return userProfile;
}
+ /**
+ * Get the account base URL for API calls
+ * For desktop apps, this directly uses the configured account URL
+ */
+ function getAccountBaseURL() {
+ return Phoenix.config.account_url.replace(/\/$/, ''); // Remove trailing slash
+ }
+
const ERR_RETRY_LATER = "retry_later";
const ERR_INVALID = "invalid";
@@ -408,6 +416,7 @@ define(function (require, exports, module) {
secureExports.signOutAccount = signOutAccount;
secureExports.getProfile = getProfile;
secureExports.verifyLoginStatus = () => _verifyLogin(false);
+ secureExports.getAccountBaseURL = getAccountBaseURL;
}
// public exports
diff --git a/src/services/profile-menu.js b/src/services/profile-menu.js
index aa10e15210..8da38fcfb1 100644
--- a/src/services/profile-menu.js
+++ b/src/services/profile-menu.js
@@ -1,6 +1,7 @@
define(function (require, exports, module) {
const Mustache = require("thirdparty/mustache/mustache"),
PopUpManager = require("widgets/PopUpManager"),
+ ThemeManager = require("view/ThemeManager"),
Strings = require("strings");
const KernalModeTrust = window.KernalModeTrust;
@@ -211,6 +212,78 @@ define(function (require, exports, module) {
/* eslint-disable-next-line*/
customElements.define ('secure-name', SecureName); // space is must in define ( to prevent build fail
+ /**
+ * Load user details iframe with secure user information
+ */
+ function _loadUserDetailsIframe() {
+ if (!Phoenix.isNativeApp && $popup) {
+ const $iframe = $popup.find("#user-details-frame");
+ const $secureName = $popup.find(".user-name secure-name");
+ const $secureEmail = $popup.find(".user-email secure-email");
+
+ if ($iframe.length) {
+ // Get account base URL for iframe using login service
+ const accountBaseURL = KernalModeTrust.loginService.getAccountBaseURL();
+ const currentTheme = ThemeManager.getCurrentTheme();
+ const nameColor = (currentTheme && currentTheme.dark) ? "FFFFFF" : "000000";
+
+ // Configure iframe URL with styling parameters
+ const iframeURL = `${accountBaseURL}/getUserDetailFrame?` +
+ `includeName=true&` +
+ `nameFontSize=14px&` +
+ `emailFontSize=12px&` +
+ `nameColor=%23${nameColor}&` +
+ `emailColor=%23666666&` +
+ `backgroundColor=transparent`;
+
+ // Listen for iframe load events
+ const messageHandler = function(event) {
+ // Only accept messages from trusted account domain
+ // Handle proxy case where accountBaseURL is '/proxy/accounts'
+ let trustedOrigin;
+ if (accountBaseURL.startsWith('/proxy/accounts')) {
+ // For localhost with proxy, accept messages from current origin
+ trustedOrigin = window.location.origin;
+ } else {
+ // For production, get origin from account URL
+ trustedOrigin = new URL(accountBaseURL).origin;
+ }
+
+ if (event.origin !== trustedOrigin) {
+ return;
+ }
+
+ if (event.data && event.data.loaded) {
+ // Hide secure DOM elements and show iframe
+ $secureName.hide();
+ $secureEmail.hide();
+ $iframe.show();
+
+ // Adjust iframe height based on content
+ $iframe.css('height', '36px'); // Approximate height for name + email
+
+ // Remove event listener
+ window.removeEventListener('message', messageHandler);
+ }
+ };
+
+ // Add message listener
+ window.addEventListener('message', messageHandler);
+
+ // Set iframe source to load user details
+ $iframe.attr('src', iframeURL);
+
+ // Fallback timeout - if iframe doesn't load in 5 seconds, keep secure elements
+ setTimeout(() => {
+ if ($iframe.is(':hidden')) {
+ console.log('User details iframe failed to load, keeping secure elements');
+ window.removeEventListener('message', messageHandler);
+ }
+ }, 5000);
+ }
+ }
+ }
+
/**
* Shows the user profile popup when the user is logged in
*/
@@ -271,6 +344,9 @@ define(function (require, exports, module) {
});
_setupDocumentClickHandler();
+
+ // Load user details iframe for browser apps (after popup is created)
+ _loadUserDetailsIframe();
}
/**
diff --git a/src/services/readme-login-browser-no_dist.md b/src/services/readme-login-browser-no_dist.md
index 87c8946fa4..85acca4f92 100644
--- a/src/services/readme-login-browser-no_dist.md
+++ b/src/services/readme-login-browser-no_dist.md
@@ -6,6 +6,11 @@ This document provides comprehensive documentation for integrating with the Phoe
The Phoenix browser application uses a login service to authenticate users across the phcode.dev domain ecosystem. The login service handles user authentication, session management, and provides secure API endpoints for login operations.
+**Key Features:**
+- Domain-wide session management using session cookies
+- Secure user profile display via iframe integration
+- Proxy server support for localhost development
+
**Key Files:**
- `src/services/login-browser.js` - Main browser login implementation
- `serve-proxy.js` - Proxy server for localhost development
@@ -122,9 +127,15 @@ The login service provides these key endpoints:
### Authentication
- `POST /signOutPost` - Sign out user (new endpoint with proper JSON handling)
-- `GET /resolveBrowserSession` - Validate and resolve current session
+- `GET /resolveBrowserSession` - Validate and resolve current session (returns masked user data for security)
- `GET /signOut` - Legacy signout endpoint (deprecated for browser use)
+### User Profile Display
+- `GET /getUserDetailFrame` - Returns HTML iframe with full user details for secure display
+ - Query parameters for styling: `includeName`, `nameFontSize`, `emailFontSize`, `nameColor`, `emailColor`, `backgroundColor`
+ - CSP-protected to only allow embedding in trusted domains
+ - Cross-origin communication via postMessage when loaded
+
### Session Management
- Session validation through `session` cookie
- Automatic session invalidation on logout
@@ -187,6 +198,12 @@ Browser (localhost:8000) → /proxy/accounts/* → serve-proxy.js
- Session cookies should have appropriate expiration times
- Logout should properly invalidate sessions on both client and server
+### User Data Security
+- **Masked API Data**: The `resolveBrowserSession` endpoint returns masked user data (e.g., "J***", "j***@g***.com") to prevent exposure to browser extensions
+- **Secure iframe Display**: Full user details are displayed via iframe from trusted account server
+- **CSP Protection**: iframe is protected by Content Security Policy headers restricting embedding domains
+- **Cross-Origin Safety**: iframe communication uses secure postMessage protocol
+
---
-For browser implementation details, see the source code in `src/services/login-browser.js` and related files. For desktop authentication, see `src/services/login-desktop.js` and `readme-login-desktop-no_dist.md`.
\ No newline at end of file
+For browser implementation details, see the source code in `src/services/login-browser.js` and related files. For desktop authentication, see `src/services/login-desktop.js` and `readme-login-desktop-no_dist.md`.