From 26047b5852e0810e85341370ea0bd848ceeccb69 Mon Sep 17 00:00:00 2001 From: abose Date: Sat, 30 Aug 2025 12:43:23 +0530 Subject: [PATCH 1/2] fix: in localhost login dev server, this was not working --- serve-proxy.js | 3 --- 1 file changed, 3 deletions(-) diff --git a/serve-proxy.js b/serve-proxy.js index 8c3d236e54..01a870bc02 100644 --- a/serve-proxy.js +++ b/serve-proxy.js @@ -2,7 +2,6 @@ /* eslint-env node */ const http = require('http'); -const https = require('https'); const url = require('url'); const path = require('path'); const fs = require('fs'); @@ -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 From 9618c5025ca60e04075ec342a6eb230575e7c2b0 Mon Sep 17 00:00:00 2001 From: abose Date: Sat, 30 Aug 2025 14:34:08 +0530 Subject: [PATCH 2/2] feat: add secure iframe user details for browser login Implement iframe integration to display full user details securely in browser profile popup, avoiding masked data exposure to extensions. Adds consistent getAccountBaseURL API across both login services and proper proxy URL handling for localhost development. --- serve-proxy.js | 4 +- src/services/html/profile-popup.html | 3 +- src/services/login-browser.js | 1 + src/services/login-desktop.js | 9 +++ src/services/profile-menu.js | 76 ++++++++++++++++++++ src/services/readme-login-browser-no_dist.md | 21 +++++- 6 files changed, 109 insertions(+), 5 deletions(-) diff --git a/serve-proxy.js b/serve-proxy.js index 01a870bc02..4773be090f 100644 --- a/serve-proxy.js +++ b/serve-proxy.js @@ -8,8 +8,8 @@ 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 = { 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`.