Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,7 @@
"_majorVersionBump": "gulp majorVersionBump",
"serve": "node serve-proxy.js . -p 8000 -c-1",
"serveLocalAccount": "node serve-proxy.js . -p 8000 -c-1 --localAccount",
"serveStagingAccount": "node serve-proxy.js . -p 8000 -c-1 --stagingAccount",
"_serveWithWebCacheHelp": "echo !!!Make sure to npm run release:dev/stageing/prod before testing the cache!!!",
"serveWithWebCache": "npm run _releaseWebCache && npm run _serveWithWebCacheHelp && http-server ./dist -p 8000 -c-1",
"serveExternal": "node serve-proxy.js . -p 8000 -a 0.0.0.0 --log-ip -c-1",
Expand Down
56 changes: 50 additions & 6 deletions serve-proxy.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,12 @@ const path = require('path');
const fs = require('fs');
const httpProxy = require('http-proxy');

const ACCOUNT_PROD = 'https://account.phcode.dev';
const ACCOUNT_STAGING = 'https://account-stage.phcode.dev';
const ACCOUNT_DEV = 'http://localhost:5000';

// Account server configuration - switch between local and production
let accountServer = 'https://account.phcode.dev'; // Production
let accountServer = ACCOUNT_PROD; // Production
// Set to local development server if --localAccount flag is provided

// Default configuration
Expand All @@ -24,6 +28,8 @@ let config = {
// Parse command line arguments
function parseArgs() {
const args = process.argv.slice(2);
let hasLocalAccount = false;
let hasStagingAccount = false;

for (let i = 0; i < args.length; i++) {
const arg = args[i];
Expand All @@ -46,11 +52,21 @@ function parseArgs() {
} else if (arg === '--log-ip') {
config.logIp = true;
} else if (arg === '--localAccount') {
accountServer = 'http://localhost:5000';
hasLocalAccount = true;
accountServer = ACCOUNT_DEV;
} else if (arg === '--stagingAccount') {
hasStagingAccount = true;
accountServer = ACCOUNT_STAGING;
} else if (!arg.startsWith('-')) {
config.root = path.resolve(arg);
}
}

// Check for mutually exclusive flags
if (hasLocalAccount && hasStagingAccount) {
console.error('Error: --localAccount and --stagingAccount cannot be used together');
process.exit(1);
}
}

// Create proxy server
Expand Down Expand Up @@ -81,15 +97,15 @@ proxy.on('proxyReq', (proxyReq, req) => {

// Transform referer from localhost:8000 to phcode.dev
if (originalReferer && originalReferer.includes('localhost:8000')) {
const newReferer = originalReferer.replace(/localhost:8000/g, 'phcode.dev');
const newReferer = originalReferer.replace(/http:\/\/localhost:8000/g, 'https://phcode.dev');
proxyReq.setHeader('Referer', newReferer);
} else if (!originalReferer) {
proxyReq.setHeader('Referer', 'https://phcode.dev/');
}

// Transform origin from localhost:8000 to phcode.dev
if (originalOrigin && originalOrigin.includes('localhost:8000')) {
const newOrigin = originalOrigin.replace(/localhost:8000/g, 'phcode.dev');
const newOrigin = originalOrigin.replace(/http:\/\/localhost:8000/g, 'https://phcode.dev');
proxyReq.setHeader('Origin', newOrigin);
}

Expand Down Expand Up @@ -254,6 +270,31 @@ const server = http.createServer((req, res) => {
return;
}

// Handle proxy config request
if (parsedUrl.pathname === '/proxy/config') {
const configResponse = {
accountURL: accountServer + '/'
};

if (!config.silent) {
console.log(`[CONFIG] ${req.method} ${parsedUrl.pathname} -> ${JSON.stringify(configResponse)}`);
}

const headers = {
'Content-Type': 'application/json'
};

if (config.cors) {
headers['Access-Control-Allow-Origin'] = '*';
headers['Access-Control-Allow-Methods'] = 'GET, POST, PUT, DELETE, OPTIONS';
headers['Access-Control-Allow-Headers'] = 'Origin, X-Requested-With, Content-Type, Accept, Authorization, Cache-Control';
}

res.writeHead(200, headers);
res.end(JSON.stringify(configResponse));
return;
}

// Check if this is a proxy request
if (parsedUrl.pathname.startsWith('/proxy/accounts')) {
// Extract the path after /proxy/accounts
Expand Down Expand Up @@ -288,8 +329,11 @@ const server = http.createServer((req, res) => {
}

if (!config.silent) {
const clientIp = req.headers['x-forwarded-for'] || req.connection.remoteAddress;
console.log(`[${new Date().toISOString()}] ${req.method} ${req.url}${config.logIp ? ` (${clientIp})` : ''}`);
// Skip logging PWA asset requests to reduce noise. chrome somehoe sends this every second to dev server.
if (!parsedUrl.pathname.includes('/assets/pwa/')) {
const clientIp = req.headers['x-forwarded-for'] || req.connection.remoteAddress;
console.log(`[${new Date().toISOString()}] ${req.method} ${req.url}${config.logIp ? ` (${clientIp})` : ''}`);
}
}

// Handle directory requests without trailing slash
Expand Down
3 changes: 2 additions & 1 deletion src/brackets.config.staging.json
Original file line number Diff line number Diff line change
Expand Up @@ -10,5 +10,6 @@
"bugsnagEnv" : "staging",
"app_notification_url" : "https://updates.phcode.io/appNotifications/staging/",
"app_update_url" : "https://updates.phcode.io/tauri/update-latest-pre-release.json",
"promotions_url" : "https://promotions.phcode.dev/dev/"
"promotions_url" : "https://promotions.phcode.dev/dev/",
"account_url" : "https://account-stage.phcode.dev/"
}
17 changes: 16 additions & 1 deletion src/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -446,7 +446,22 @@
loadJS('verify-dependencies-loaded.js', null, document.body);
}

function _startRequireLoop() {
async function _startRequireLoop() {
// If running on localhost, fetch proxy config to get dynamic account URL
if (window.location.hostname === 'localhost' || window.location.hostname === '127.0.0.1') {
try {
const response = await fetch('/proxy/config');
if (response.ok) {
const config = await response.json();
if (config.accountURL) {
window.AppConfig.config.account_url = config.accountURL;
console.log('Applied dynamic account URL from proxy:', config.accountURL);
}
}
} catch (error) {
console.warn('Failed to fetch proxy config, using default account URL:', error);
}
}
loadJS('thirdparty/requirejs/require.js', _requireDone, document.body, "main");
}
if(window.PhStore){
Expand Down
22 changes: 16 additions & 6 deletions src/services/login-desktop.js
Original file line number Diff line number Diff line change
Expand Up @@ -80,9 +80,19 @@ define(function (require, exports, module) {
* For desktop apps, this directly uses the configured account URL
*/
function getAccountBaseURL() {
if (location.hostname === 'localhost' || location.hostname === '127.0.0.1') {
return '/proxy/accounts';
}
return Phoenix.config.account_url.replace(/\/$/, ''); // Remove trailing slash
}

/**
* Get the account website URL for opening browser tabs
*/
function _getAccountWebURL() {
return Phoenix.config.account_url;
}

const ERR_RETRY_LATER = "retry_later";
const ERR_INVALID = "invalid";

Expand All @@ -96,7 +106,7 @@ define(function (require, exports, module) {
* never rejects.
*/
async function _resolveAPIKey(apiKey, validationCode) {
const resolveURL = `${Phoenix.config.account_url}resolveAppSessionID?appSessionID=${apiKey}&validationCode=${validationCode}`;
const resolveURL = `${getAccountBaseURL()}/resolveAppSessionID?appSessionID=${apiKey}&validationCode=${validationCode}`;
if (!navigator.onLine) {
return {err: ERR_RETRY_LATER};
}
Expand Down Expand Up @@ -196,7 +206,7 @@ define(function (require, exports, module) {
const authPortURL = _getAutoAuthPortURL();
const platformStr = PLATFORM_STRINGS[Phoenix.platform] || Phoenix.platform;
const appName = encodeURIComponent(`${Strings.APP_NAME} Desktop on ${platformStr}`);
const resolveURL = `${Phoenix.config.account_url}getAppAuthSession?autoAuthPort=${authPortURL}&appName=${appName}`;
const resolveURL = `${getAccountBaseURL()}/getAppAuthSession?autoAuthPort=${authPortURL}&appName=${appName}`;
// {"isSuccess":true,"appSessionID":"a uuid...","validationCode":"SWXP07"}
try {
if(Phoenix.isTestWindow && fetchFn === fetch){
Expand Down Expand Up @@ -254,7 +264,7 @@ define(function (require, exports, module) {
}
const {appSessionID, validationCode} = appAuthSession;
await setAutoVerificationCode(validationCode);
const appSignInURL = `${Phoenix.config.account_url}authorizeApp?appSessionID=${appSessionID}`;
const appSignInURL = `${_getAccountWebURL()}authorizeApp?appSessionID=${appSessionID}`;

// Show dialog with validation code
const dialogData = {
Expand Down Expand Up @@ -350,7 +360,7 @@ define(function (require, exports, module) {
}

async function signOutAccount() {
const resolveURL = `${Phoenix.config.account_url}logoutSession`;
const resolveURL = `${getAccountBaseURL()}/logoutSession`;
try {
let input = {
appSessionID: userProfile.apiKey
Expand Down Expand Up @@ -378,7 +388,7 @@ define(function (require, exports, module) {
Strings.SIGNED_OUT_FAILED_MESSAGE
);
dialog.done(() => {
NativeApp.openURLInDefaultBrowser(Phoenix.config.account_url + "#advanced");
NativeApp.openURLInDefaultBrowser(_getAccountWebURL() + "#advanced");
});
Metrics.countEvent(Metrics.EVENT_TYPE.AUTH, 'logoutFail', Phoenix.platform);
return;
Expand All @@ -399,7 +409,7 @@ define(function (require, exports, module) {
Strings.SIGNED_OUT_FAILED_MESSAGE
);
dialog.done(() => {
NativeApp.openURLInDefaultBrowser(Phoenix.config.account_url + "#advanced");
NativeApp.openURLInDefaultBrowser(_getAccountWebURL() + "#advanced");
});
Metrics.countEvent(Metrics.EVENT_TYPE.AUTH, 'getAppAuth', Phoenix.platform);
logger.reportError(error, "Failed to call logout calling" + resolveURL);
Expand Down
3 changes: 3 additions & 0 deletions src/services/manage-licenses.js
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,9 @@ define(function (require, exports, module) {
* Get the API base URL for license operations
*/
function _getAPIBaseURL() {
if (location.hostname === 'localhost' || location.hostname === '127.0.0.1') {
return '/proxy/accounts';
}
return Phoenix.config.account_url.replace(/\/$/, ''); // Remove trailing slash
}

Expand Down
11 changes: 6 additions & 5 deletions src/services/readme-login-browser-no_dist.md
Original file line number Diff line number Diff line change
Expand Up @@ -99,9 +99,8 @@ function _getAccountBaseURL() {
For testing with a local account server instance:

1. **Configure Proxy Server:**
- Edit `serve-proxy.js`
- **Comment out:** `const ACCOUNT_SERVER = 'https://account.phcode.dev'; // Production`
- **Uncomment:** `const ACCOUNT_SERVER = 'http://localhost:5000'; // Local development`
- use `npm run serveLocalAccount` to serve phoenix repo server, instead of using npm run serve command.
- use `npm run serveStagingAccount` to use the staging endpoint. To get access to staging server, contact team.

2. **Setup Local Account Server:**
- Start your local account development stack on `localhost:5000`
Expand All @@ -111,10 +110,12 @@ Now just visit login server at `http://localhost:5000` and login. It should work
at https://localhost:8000/src when you run phoenix code dev server via `npm run serve`. This works without any
manual cookie copy needed as the dev server sets cookies localhost wide. But if that didnt work, please see
manual cookie copy instructions below.

For staging server at https://account-stage.phcode.dev , you may need to copy cookie manually like below:

1. **Login and Copy Session:**
- Navigate to `http://localhost:5000` in browser
- Login with test credentials
- Navigate to `http://localhost:5000` in browser. (if staging, use https://account-stage.phcode.dev)
- Login with your credentials
- Copy `session` cookie value from DevTools

2. **Set Cookie in Phoenix App:**
Expand Down
28 changes: 12 additions & 16 deletions src/services/readme-login-desktop-no_dist.md
Original file line number Diff line number Diff line change
Expand Up @@ -241,25 +241,21 @@ pref.on('change', _verifyLogin);

For testing desktop authentication with a local account server:

1. **Configure Account URL:**
- Edit `src/config.json`
- Change `account_url` from `https://account.phcode.dev/` to `http://localhost:5000/` (or your local server URL)
1. **Configure Proxy Server:**
- use `npm run serveLocalAccount` to serve phoenix repo server, instead of using npm run serve command.
- use `npm run serveStagingAccount` to use the staging endpoint. To get access to staging server, contact team.

2. **Rebuild Application:**
```bash
npm run build
```

3. **Start Your Local Account Server:**
- Ensure your local account server is running on the configured port (e.g., localhost:5000)
- Verify all authentication endpoints are properly configured
2. **Setup Local Account Server:**
- Start your local account development stack on `localhost:5000`
- Ensure all login endpoints are properly configured

4. **Test Desktop Authentication:**
- Desktop app will now use your local server for all authentication calls
- Verification codes and API key resolution will go through your local server
3. **Test Desktop Authentication:**
- Desktop app will now use your local/staging server for all authentication calls
- Verification codes and API key resolution will go through your local/staging server
- Auto-verification will attempt to connect to your local account service

**Note:** Unlike browser testing which requires proxy server configuration, desktop apps simply use the `account_url` directly from config.json.
**Note:** Like browser testing which requires proxy server configuration, desktop apps also use the proxy server
for communication with backend.

## Troubleshooting

Expand Down Expand Up @@ -326,4 +322,4 @@ if(resolveResponse.userDetails) {

For desktop implementation details, see the source code in `src/services/login-desktop.js`. For browser authentication, see `src/services/login-browser.js` and `readme-login-browser-no_dist.md`.

For deeper understanding of the Kernel Mode Trust security architecture and secure credential storage implementation, refer to the Kernel Mode Trust source files (out of scope for this document).
For deeper understanding of the Kernel Mode Trust security architecture and secure credential storage implementation, refer to the Kernel Mode Trust source files (out of scope for this document).
5 changes: 2 additions & 3 deletions src/utils/Global.js
Original file line number Diff line number Diff line change
Expand Up @@ -28,8 +28,7 @@
define(function (require, exports, module) {


var configJSON = require("text!config.json"),
UrlParams = require("utils/UrlParams").UrlParams;
const UrlParams = require("utils/UrlParams").UrlParams;

// Define core brackets namespace if it isn't already defined
//
Expand Down Expand Up @@ -57,7 +56,7 @@ define(function (require, exports, module) {

// Parse src/config.json
try {
global.brackets.metadata = JSON.parse(configJSON);
global.brackets.metadata = window.AppConfig;
global.brackets.config = global.brackets.metadata.config;
} catch (err) {
console.log(err);
Expand Down
1 change: 1 addition & 0 deletions test/SpecRunner.html
Original file line number Diff line number Diff line change
Expand Up @@ -148,6 +148,7 @@
<!-- Import the phoenix browser virtual file system -->
<script src="../src/phoenix/virtualfs.js"></script>
<script src="../src/utils/EventDispatcher.js"></script>
<script src="../src/appConfig.js"></script>

<script>
// environment setup for boot. do not move out of index html!!
Expand Down
Loading